add 示例
This commit is contained in:
@@ -1,6 +1,25 @@
|
||||
---
|
||||
title: XU316音频接口控制代码示例
|
||||
description: 本文档提供了XU316音频接口控制相关的代码示例,包括串口通信协议、音频接口配置等,帮助开发者快速实现XU316与MCU的通信功能。
|
||||
keywords: XU316开发, 音频接口控制, MCU通信, I2S配置, 串口协议, 音频采样率, DSD配置
|
||||
---
|
||||
|
||||
# XU316音频接口控制代码示例
|
||||
|
||||
```
|
||||
## 文档说明
|
||||
|
||||
本文档提供了XU316音频接口控制相关的代码示例,主要包含以下内容:
|
||||
1. 串口通信协议定义
|
||||
2. 音频接口配置参数
|
||||
3. 音频采样率和通道配置
|
||||
4. 音量控制参数设置
|
||||
|
||||
这些代码示例可以帮助开发者快速实现XU316与MCU的通信功能,以及配置各种音频接口参数。
|
||||
|
||||
## 串口通信协议
|
||||
|
||||
### 协议定义
|
||||
```c
|
||||
#define SWAP16(x) ((((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00))
|
||||
#define SWAP32(x) ((((x) >> 24) & 0x000000FF) | (((x) >> 8) & 0x0000FF00) | (((x) << 8) & 0x00FF0000) | (((x) << 24) & 0xFF000000))
|
||||
/*协议解析*/
|
||||
@@ -19,7 +38,10 @@ typedef struct
|
||||
uint8_t check; // 校验和
|
||||
uint8_t tail; // 帧尾 0x55
|
||||
} uart_frame_t;
|
||||
```
|
||||
|
||||
### 串口缓冲区管理
|
||||
```c
|
||||
/*串口*/
|
||||
/* buffer sizes */
|
||||
#define RX_BUFFER_SIZE 256
|
||||
@@ -49,9 +71,10 @@ typedef enum
|
||||
} log_dir_t;
|
||||
```
|
||||
|
||||
## 音频接口配置
|
||||
|
||||
|
||||
```
|
||||
### 接口模式配置
|
||||
```c
|
||||
// I2S主从模式配置
|
||||
#define I2S_MODE I2S_MODE_MASTER // I2S主模式,XU316作为I2S主设备
|
||||
// 同步模式配置
|
||||
@@ -68,7 +91,10 @@ typedef enum
|
||||
#define ADAT_OUT_MODE ADAT_OUT_MODE_ENABLE // ADAT输出功能启用
|
||||
// DSD输出接口配置 (DSD是直接数字流,用于高解析度音频)
|
||||
#define DSD_OUT_MODE DSD_OUT_MODE_ENABLE // DSD输出功能启用
|
||||
```
|
||||
|
||||
### 音频参数配置
|
||||
```c
|
||||
// 初始化音频采样率
|
||||
#define AUDIO_SAMPLE_RATE (uint8_t)AUDIO_SAMPLE_RATE_44100
|
||||
#define MQA_MODE MQA_MODE_DISABLE
|
||||
@@ -87,6 +113,23 @@ typedef enum
|
||||
#define DAC_L_VOLUME 30
|
||||
// DAC右声道默认音量 1 见DAC音量字段说明
|
||||
#define DAC_R_VOLUME 20
|
||||
```
|
||||
|
||||
<!-- 结构化数据标记 -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "TechArticle",
|
||||
"headline": "XU316音频接口控制代码示例",
|
||||
"description": "本文档提供了XU316音频接口控制相关的代码示例,包括串口通信协议、音频接口配置等,帮助开发者快速实现XU316与MCU的通信功能。",
|
||||
"keywords": "XU316开发, 音频接口控制, MCU通信, I2S配置, 串口协议, 音频采样率, DSD配置",
|
||||
"author": {
|
||||
"@type": "Organization",
|
||||
"name": "Phaten Audio"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -1,17 +1,36 @@
|
||||
**命令的相关宏**
|
||||
---
|
||||
title: XU316与MCU通信协议命令宏定义
|
||||
description: 本文档提供了XU316与MCU通信协议相关的命令宏定义,包括帧格式、命令长度、通信协议等,帮助开发者实现XU316与MCU的通信功能。
|
||||
keywords: XU316通信协议, MCU命令宏定义, 音频格式定义, 通信帧格式, 命令数据结构, 音频类型定义
|
||||
---
|
||||
|
||||
**// 帧格式定义**
|
||||
# XU316与MCU通信协议命令宏定义
|
||||
|
||||
```
|
||||
## 文档说明
|
||||
|
||||
本文档提供了XU316与MCU通信协议相关的命令宏定义,主要包含以下内容:
|
||||
1. 通信帧格式定义
|
||||
2. MCU命令数据长度定义
|
||||
3. 通信协议命令字枚举
|
||||
4. 音频格式和类型定义
|
||||
5. 命令数据结构定义
|
||||
|
||||
这些宏定义和数据结构是XU316与MCU通信的基础,开发者需要正确理解和使用这些定义来实现通信功能。
|
||||
|
||||
## 通信帧格式
|
||||
|
||||
### 基本帧格式定义
|
||||
```c
|
||||
#define FRAME_HEADER_H 0x55
|
||||
#define FRAME_HEADER_L 0xAA
|
||||
#define PROTOCOL_VERSION 0x01
|
||||
#define PROTOCOL_VERSION_RX 0x03
|
||||
```
|
||||
|
||||
**/* MCU 命令接收数据长度宏定义 */**
|
||||
## 命令数据长度定义
|
||||
|
||||
```
|
||||
### XU316命令数据长度
|
||||
```c
|
||||
#define CMD00_XU316_DATA_LEN 0x11 // 0x00 命令:开始启动(启动选项)
|
||||
#define CMD01_XU316_DATA_LEN 0x00 // 0x01 命令:读取产品信息(60字节固件信息)
|
||||
#define CMD02_XU316_DATA_LEN 0x00 // 0x02 命令:读取上电配置(14字节配置参数)
|
||||
@@ -33,9 +52,8 @@
|
||||
#define CMD_HID_TRANSPARENT_DATA_LEN 0x39 // 0xEE 命令:HID透传/OTA升级(57字节)
|
||||
```
|
||||
|
||||
**/* MCU 命令回复数据长度宏定义 */**
|
||||
|
||||
```
|
||||
### MCU命令数据长度
|
||||
```c
|
||||
#define CMD00_MCU_DATA_LEN 0x01 // 0x00 命令:开始启动(启动选项)
|
||||
#define CMD01_MCU_DATA_LEN 0x3C // 0x01 命令:读取产品信息(60字节固件信息)
|
||||
#define CMD02_MCU_DATA_LEN 0x0E // 0x02 命令:读取上电配置(14字节配置参数)
|
||||
@@ -57,13 +75,10 @@
|
||||
#define CMD_HID_TRANSPARENT_MCU_DATA_LEN 0x39 // 0xEE 命令:HID透传/OTA升级(57字节)
|
||||
```
|
||||
|
||||
## 通信协议命令定义
|
||||
|
||||
|
||||
**MCU 通信协议命令字枚举**
|
||||
|
||||
**遵循分层分类原则,按功能模块划分命名空间**
|
||||
|
||||
```
|
||||
### 命令字枚举
|
||||
```c
|
||||
typedef enum
|
||||
{
|
||||
/****** 基础控制命令 (0x00-0x05) ******/
|
||||
@@ -83,7 +98,7 @@ typedef enum
|
||||
CMD_SET_AUDIO_MODE = 0x23, // 音频模式设置
|
||||
CMD_SET_PLAY_VOL = 0x24, // 播放音量设置
|
||||
CMD_SET_REC_VOL = 0x25, // 录音音量设置
|
||||
CMD_SPECIAL_UNMUTE = 0x27, // 特殊静音解除
|
||||
CMD_SPECIAL_UNMUTE = 0x27, // 特殊静音解除
|
||||
CMD_SET_AUDIO_FORMAT_DELAY = 0x28, // 音频格式延迟设置
|
||||
|
||||
CMD_HID_TRANSPARENT = 0xEE, // HID透传/OTA升级命令
|
||||
@@ -93,21 +108,24 @@ typedef enum
|
||||
} mcu_command_t;
|
||||
```
|
||||
|
||||
### 启动选项枚举(Bitmask模式)
|
||||
|
||||
!!! note
|
||||
**启动选项枚举(Bitmask模式)**
|
||||
**使用uint8_t确保单字节存储,支持多选项组合**
|
||||
|
||||
**启动选项枚举(Bitmask模式)**
|
||||
|
||||
**使用uint8_t确保单字节存储,支持多选项组合**
|
||||
|
||||
```
|
||||
```c
|
||||
typedef enum
|
||||
{
|
||||
BOOT_OPTION_USE_DEFAULTS = 0x00, // 使用所有默认配置
|
||||
BOOT_OPTION_UPDATE_BASIC_INFO = 0x01, // 更新基础产品信息 (bit0)
|
||||
BOOT_OPTION_UPDATE_POWER_CFG = 0x02, // 更新上电配置信息 (bit1)
|
||||
BOOT_OPTION_UPDATE_OTHER_CFG = 0x04 // 预留配置,目前没用 (bit2)
|
||||
BOOT_OPTION_UPDATE_OTHER_CFG = 0x04 // 预留配置,目前没用 (bit2)
|
||||
} boot_option_t;
|
||||
```
|
||||
|
||||
### 媒体控制枚举
|
||||
```c
|
||||
typedef enum
|
||||
{
|
||||
MEDIA_KEY_VOLUME_UP = 0x00, // 音量增加
|
||||
@@ -124,13 +142,14 @@ typedef enum
|
||||
} media_control_t;
|
||||
```
|
||||
|
||||
## 音频格式定义
|
||||
|
||||
!!! note
|
||||
**音频流格式枚举(兼容AES67-2020标准)**
|
||||
**显式指定底层类型为uint8_t确保1字节存储**
|
||||
|
||||
**音频流格式枚举(兼容AES67-2020标准)**
|
||||
|
||||
**显式指定底层类型为uint8_t确保1字节存储**
|
||||
|
||||
```
|
||||
### 音频流格式枚举
|
||||
```c
|
||||
typedef enum
|
||||
{
|
||||
// PCM采样率格式 (0x00-0x10)
|
||||
@@ -195,13 +214,12 @@ typedef enum
|
||||
} audio_format_t;
|
||||
```
|
||||
|
||||
### 音频类型枚举
|
||||
!!! note
|
||||
**音频类型枚举(兼容AES67-2020标准)**
|
||||
**显式指定底层类型为uint8_t确保1字节存储**
|
||||
|
||||
|
||||
**音频类型枚举**
|
||||
|
||||
**显式指定底层类型为uint8_t确保1字节存储**
|
||||
|
||||
```
|
||||
```c
|
||||
typedef enum
|
||||
{
|
||||
AUDIO_TYPE_PCM = 0x00, // PCM标准音频
|
||||
@@ -216,7 +234,10 @@ typedef enum
|
||||
} audio_type_t;
|
||||
```
|
||||
|
||||
```
|
||||
## 命令数据结构
|
||||
|
||||
### 数据结构定义
|
||||
```c
|
||||
typedef uint8_t byte_pair[2];
|
||||
// 命令数据结构体
|
||||
typedef struct __attribute__((packed))
|
||||
@@ -246,3 +267,17 @@ typedef struct __attribute__((packed))
|
||||
} mcu_data_t;
|
||||
```
|
||||
|
||||
<!-- 结构化数据标记 -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "TechArticle",
|
||||
"headline": "XU316与MCU通信协议命令宏定义",
|
||||
"description": "本文档提供了XU316与MCU通信协议相关的命令宏定义,包括帧格式、命令长度、通信协议等,帮助开发者实现XU316与MCU的通信功能。",
|
||||
"keywords": "XU316通信协议, MCU命令宏定义, 音频格式定义, 通信帧格式, 命令数据结构, 音频类型定义",
|
||||
"author": {
|
||||
"@type": "Organization",
|
||||
"name": "Phaten Audio"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,31 +1,42 @@
|
||||
**命令相关**
|
||||
---
|
||||
title: XU316与MCU通信协议参考
|
||||
description: XU316与MCU之间的通信协议详细说明,包括数据结构、命令格式和处理流程
|
||||
keywords: XU316, MCU, 通信协议, 命令参考
|
||||
hide:
|
||||
-toc
|
||||
---
|
||||
<!-- --8<-- "common/phaten_xmos_support_img.md" -->
|
||||
|
||||
```
|
||||
#define RING_BUFFER_SIZE 256 // 环形缓冲区大小
|
||||
# XU316与MCU通信协议参考
|
||||
|
||||
## 1. 基础数据结构
|
||||
|
||||
### 1.1 环形缓冲区
|
||||
```c
|
||||
#define RING_BUFFER_SIZE 256 // 环形缓冲区大小,用于UART通信缓存
|
||||
|
||||
typedef struct {
|
||||
uint8_t buffer[RING_BUFFER_SIZE];
|
||||
volatile uint16_t head; // 写入位置
|
||||
volatile uint16_t tail; // 读取位置
|
||||
uint8_t buffer[RING_BUFFER_SIZE]; // 数据存储区
|
||||
volatile uint16_t head; // 写入位置指针
|
||||
volatile uint16_t tail; // 读取位置指针
|
||||
volatile uint16_t count; // 当前数据量
|
||||
} ring_buffer_t;
|
||||
```
|
||||
|
||||
```
|
||||
// 定义音频模式数组
|
||||
### 1.2 音频模式定义
|
||||
```c
|
||||
// 音频模式配置数组,每个模式包含5字节配置数据
|
||||
static const uint8_t audio_modes[][5] = {
|
||||
{0x00, 0x80, 0xa9, 0x00, 0x01}, // Usb-no-mqa
|
||||
{0x00, 0x80, 0x01, 0x00, 0x02}, // UAC1
|
||||
{0x10, 0x80, 0x65, 0x10, 0x03}, // COAX
|
||||
{0x00, 0x80, 0x65, 0x10, 0x04}, // OPT
|
||||
{0x00, 0x80, 0xc5, 0x08, 0x05}, // SPDIF OUT
|
||||
{0x00, 0x82, 0xd5, 0x81, 0x06}, // I2S IN
|
||||
{0x20, 0x80, 0x65, 0x10, 0x07} // HDMI
|
||||
{0x00, 0x80, 0xa9, 0x00, 0x01}, // USB-no-mqa模式
|
||||
{0x00, 0x80, 0x01, 0x00, 0x02}, // UAC1模式
|
||||
{0x10, 0x80, 0x65, 0x10, 0x03}, // COAX模式
|
||||
{0x00, 0x80, 0x65, 0x10, 0x04}, // OPT模式
|
||||
{0x00, 0x80, 0xc5, 0x08, 0x05}, // SPDIF OUT模式
|
||||
{0x00, 0x82, 0xd5, 0x81, 0x06}, // I2S IN模式
|
||||
{0x20, 0x80, 0x65, 0x10, 0x07} // HDMI模式
|
||||
};
|
||||
```
|
||||
|
||||
```
|
||||
// 定义模式名称数组
|
||||
// 对应的模式名称数组
|
||||
static const char *mode_names[] = {
|
||||
"USB-no-mqa",
|
||||
"UAC1",
|
||||
@@ -37,128 +48,119 @@ static const char *mode_names[] = {
|
||||
};
|
||||
```
|
||||
|
||||
**上电时的打印信息**
|
||||
## 2. 初始化与配置
|
||||
|
||||
```
|
||||
### 2.1 设备初始化信息打印
|
||||
```c
|
||||
#define AUDIO_MODE_COUNT (sizeof(audio_modes) / sizeof(audio_modes[0]))
|
||||
|
||||
void print_init_info(void)
|
||||
{
|
||||
log_data(LOG_USER, "----------Device initialized----------\n");
|
||||
// 打印UAC1.0设备信息
|
||||
log_data(LOG_USER, "VID1: %02X%02X", mcu_data.vid_uac1[0], mcu_data.vid_uac1[1]);
|
||||
log_data(LOG_USER, "PID1: %02X%02X", mcu_data.pid_uac1[0], mcu_data.pid_uac1[1]);
|
||||
// 打印UAC2.0设备信息
|
||||
log_data(LOG_USER, "VID2: %02X%02X", mcu_data.vid_uac2[0], mcu_data.vid_uac2[1]);
|
||||
log_data(LOG_USER, "PID2: %02X%02X", mcu_data.pid_uac2[0], mcu_data.pid_uac2[1]);
|
||||
// 打印产品信息
|
||||
log_data(LOG_USER, "Manufacturer: %s", mcu_data.product_manufacturer);
|
||||
log_data(LOG_USER, "Name: %s", mcu_data.product_name);
|
||||
log_data(LOG_USER, "Serial: %s", mcu_data.product_serial);
|
||||
log_data(LOG_USER, "Basic Info CRC: %02X%02X%02X%02X", mcu_data.basic_info_crc[0], mcu_data.basic_info_crc[1], mcu_data.basic_info_crc[2], mcu_data.basic_info_crc[3]);
|
||||
log_data(LOG_USER, "Power Config CRC: %02X%02X%02X%02X", mcu_data.power_cfg_crc[0], mcu_data.power_cfg_crc[1], mcu_data.power_cfg_crc[2], mcu_data.power_cfg_crc[3]);
|
||||
// 打印CRC校验信息
|
||||
log_data(LOG_USER, "Basic Info CRC: %02X%02X%02X%02X",
|
||||
mcu_data.basic_info_crc[0], mcu_data.basic_info_crc[1],
|
||||
mcu_data.basic_info_crc[2], mcu_data.basic_info_crc[3]);
|
||||
log_data(LOG_USER, "Power Config CRC: %02X%02X%02X%02X",
|
||||
mcu_data.power_cfg_crc[0], mcu_data.power_cfg_crc[1],
|
||||
mcu_data.power_cfg_crc[2], mcu_data.power_cfg_crc[3]);
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
// 初始化环形缓冲区
|
||||
### 2.2 环形缓冲区初始化
|
||||
```c
|
||||
void ring_buffer_init(void) {
|
||||
uart_ring_buffer.head = 0;
|
||||
uart_ring_buffer.tail = 0;
|
||||
uart_ring_buffer.count = 0;
|
||||
uart_ring_buffer.head = 0; // 初始化写入位置
|
||||
uart_ring_buffer.tail = 0; // 初始化读取位置
|
||||
uart_ring_buffer.count = 0; // 初始化数据计数
|
||||
}
|
||||
```
|
||||
|
||||
**产品信息初始化**
|
||||
|
||||
```
|
||||
### 2.3 产品信息初始化
|
||||
```c
|
||||
void xu316_init(void)
|
||||
{
|
||||
// Usb-no-mqa: 0x00, 0x80, 0xa9, 0x00, 0x01
|
||||
// UAC1: 0x00, 0x80, 0x01, 0x00, 0x02
|
||||
// COAX: 0x10, 0x80, 0x65, 0x10, 0x03
|
||||
// OPT: 0x00, 0x80, 0x65, 0x10, 0x04
|
||||
// SPDIF OUT: 0x00, 0x80, 0xc5, 0x08, 0x05
|
||||
// I2S IN: 0x00, 0x82, 0xd5, 0x81, 0x06
|
||||
// HDMI: 0x20, 0x80, 0x65, 0x10, 0x07
|
||||
|
||||
uint8_t audio_mode[5] = {0x00, 0x80, 0xa9, 0x00, 0x01}; // usb uac2.0
|
||||
// 设置 UAC1.0 设备的 VID (Vendor ID)
|
||||
// 默认音频模式配置(USB UAC2.0)
|
||||
uint8_t audio_mode[5] = {0x00, 0x80, 0xa9, 0x00, 0x01};
|
||||
|
||||
// 配置UAC1.0设备信息
|
||||
mcu_data.vid_uac1[0] = 0x20;
|
||||
mcu_data.vid_uac1[1] = 0xB1; // VID = 0x20B1
|
||||
|
||||
// 设置 UAC1.0 设备的 PID (Product ID)
|
||||
mcu_data.vid_uac1[1] = 0xB1; // VID = 0x20B1
|
||||
mcu_data.pid_uac1[0] = 0x00;
|
||||
mcu_data.pid_uac1[1] = 0x17; // PID = 0x0017
|
||||
mcu_data.pid_uac1[1] = 0x17; // PID = 0x0017
|
||||
|
||||
// 设置 UAC2.0 设备的 VID
|
||||
// 配置UAC2.0设备信息
|
||||
mcu_data.vid_uac2[0] = 0x20;
|
||||
mcu_data.vid_uac2[1] = 0xB1; // VID = 0x20B1
|
||||
|
||||
// 设置 UAC2.0 设备的 PID
|
||||
mcu_data.vid_uac2[1] = 0xB1; // VID = 0x20B1
|
||||
mcu_data.pid_uac2[0] = 0x00;
|
||||
mcu_data.pid_uac2[1] = 0x16; // PID = 0x0016
|
||||
mcu_data.pid_uac2[1] = 0x16; // PID = 0x0016
|
||||
|
||||
// 设置设备制造商名称
|
||||
// 配置产品信息
|
||||
memcpy(mcu_data.product_manufacturer, "Phaten", 6);
|
||||
// 设置产品名称
|
||||
memcpy(mcu_data.product_name, "XMOS XU316", 11);
|
||||
// 设置产品序列号
|
||||
memcpy(mcu_data.product_serial, "123456789ABCDEF", 15);
|
||||
|
||||
// 计算基础信息的CRC32校验值(包含VID、PID、制造商信息等,总长56字节)
|
||||
|
||||
crc = calculate_crc32(mcu_data.vid_uac1, 56);
|
||||
// 存储CRC校验值(大端序)
|
||||
// 计算并存储基础信息CRC32校验值(56字节)
|
||||
crc = calculate_crc32(mcu_data.vid_uac1, 56);
|
||||
mcu_data.basic_info_crc[0] = (crc >> 24) & 0xFF;
|
||||
mcu_data.basic_info_crc[1] = (crc >> 16) & 0xFF;
|
||||
mcu_data.basic_info_crc[2] = (crc >> 8) & 0xFF;
|
||||
mcu_data.basic_info_crc[3] = crc & 0xFF;
|
||||
|
||||
// 初始化设备启动状态
|
||||
// 初始化设备状态和音频配置
|
||||
mcu_data.startup_status = 0x00;
|
||||
|
||||
memcpy(&mcu_data.audio_mode, audio_mode, 5);
|
||||
// 设置静音持续时间(0x190 = 400ms)
|
||||
|
||||
// 配置静音持续时间(400ms)
|
||||
mcu_data.mute_duration[0] = MUTE_DURATION_CONFIG >> 8;
|
||||
mcu_data.mute_duration[1] = MUTE_DURATION_CONFIG;
|
||||
|
||||
// 初始化麦克风音量
|
||||
// 初始化音量设置
|
||||
mcu_data.mic_volume = MIC_VOLUME_CONFIG;
|
||||
// 初始化左右声道DAC音量
|
||||
mcu_data.dac_l_volume = DAC_L_VOLUME_CONFIG;
|
||||
mcu_data.dac_r_volume = DAC_R_VOLUME_CONFIG;
|
||||
|
||||
// 计算电源配置的CRC32校验值(音频模式相关配置,长度0x0a字节)
|
||||
|
||||
crc = calculate_crc32((uint8_t *)&mcu_data.audio_mode, 0x0a);
|
||||
// 存储CRC校验值(大端序)
|
||||
// 计算并存储电源配置CRC32校验值(10字节)
|
||||
crc = calculate_crc32((uint8_t *)&mcu_data.audio_mode, 0x0a);
|
||||
mcu_data.power_cfg_crc[0] = (crc >> 24) & 0xFF;
|
||||
mcu_data.power_cfg_crc[1] = (crc >> 16) & 0xFF;
|
||||
mcu_data.power_cfg_crc[2] = (crc >> 8) & 0xFF;
|
||||
mcu_data.power_cfg_crc[3] = crc & 0xFF;
|
||||
|
||||
// 初始化环形缓冲区
|
||||
// 初始化通信缓冲区
|
||||
ring_buffer_init();
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
**从环形缓冲区读写数据**
|
||||
## 3. 通信缓冲区操作
|
||||
|
||||
```
|
||||
### 3.1 环形缓冲区操作函数
|
||||
```c
|
||||
// 写入数据到环形缓冲区
|
||||
uint8_t ring_buffer_write(uint8_t *data, uint16_t len) {
|
||||
uint16_t i;
|
||||
for(i = 0; i < len; i++) {
|
||||
// 检查缓冲区是否已满
|
||||
if(uart_ring_buffer.count >= RING_BUFFER_SIZE) {
|
||||
return 0; // 缓冲区满,写入失败
|
||||
}
|
||||
|
||||
uart_ring_buffer.buffer[uart_ring_buffer.head] = data[i];
|
||||
uart_ring_buffer.head = (uart_ring_buffer.head + 1) % RING_BUFFER_SIZE;
|
||||
uart_ring_buffer.count++;
|
||||
}
|
||||
return 1; // 写入成功
|
||||
|
||||
}
|
||||
|
||||
// 从环形缓冲区读取数据
|
||||
@@ -167,107 +169,87 @@ uint8_t ring_buffer_read(uint8_t *data, uint16_t len) {
|
||||
if(uart_ring_buffer.count < len) {
|
||||
return 0; // 数据不足
|
||||
}
|
||||
|
||||
|
||||
for(i = 0; i < len; i++) {
|
||||
data[i] = uart_ring_buffer.buffer[uart_ring_buffer.tail];
|
||||
uart_ring_buffer.tail = (uart_ring_buffer.tail + 1) % RING_BUFFER_SIZE;
|
||||
uart_ring_buffer.count--;
|
||||
}
|
||||
return 1; // 读取成功
|
||||
|
||||
}
|
||||
// 预读
|
||||
|
||||
// 预读数据(不移动读取指针)
|
||||
uint8_t ring_buffer_peek(uint8_t *data, uint16_t len) {
|
||||
uint16_t i;
|
||||
uint16_t temp_tail = uart_ring_buffer.tail;
|
||||
|
||||
for(i = 0; i < len; i++) {
|
||||
data[i] = uart_ring_buffer.buffer[temp_tail];
|
||||
temp_tail = (temp_tail + 1) % RING_BUFFER_SIZE;
|
||||
}
|
||||
return 0; // 预读成功
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 校验和计算
|
||||
|
||||
|
||||
**计算CRC32**
|
||||
|
||||
```
|
||||
### 4.1 CRC32计算
|
||||
```c
|
||||
uint32_t calculate_crc32(const uint8_t *buffer, uint32_t length)
|
||||
{
|
||||
uint32_t crc = 0xFFFFFFFF;
|
||||
const uint32_t poly = 0xEDB88320;
|
||||
const uint32_t poly = 0xEDB88320; // CRC32多项式
|
||||
|
||||
for (size_t i = 0; i < length; i++)
|
||||
{
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
crc ^= buffer[i];
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
if (crc & 1)
|
||||
{
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (crc & 1) {
|
||||
crc = (crc >> 1) ^ poly;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
crc >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ~crc;
|
||||
|
||||
return ~crc; // 返回CRC32校验值
|
||||
}
|
||||
|
||||
// 计算简单校验和
|
||||
uint8_t xu316_calc_checksum(uint8_t *data, uint8_t len)
|
||||
{
|
||||
uint8_t sum = 0;
|
||||
for (uint8_t i = 0; i < len; i++)
|
||||
{
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
sum += data[i];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 通信协议处理
|
||||
|
||||
|
||||
```
|
||||
// 校验帧数据
|
||||
// buf: 输入数据数组
|
||||
// len: 数据长度
|
||||
// 返回值: 0-校验失败,1-校验成功
|
||||
### 5.1 帧校验
|
||||
```c
|
||||
// 校验帧数据完整性
|
||||
uint8_t uart_frame_check(uint8_t *buf, uint8_t len)
|
||||
{
|
||||
// 检查最小长度
|
||||
if (len < 6)
|
||||
{ // 帧头(2) + 版本(1) + 命令(1) + 长度(2) + 校验(1)
|
||||
// 检查最小长度要求
|
||||
if (len < 6) { // 帧头(2) + 版本(1) + 命令(1) + 长度(2) + 校验(1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 检查帧头
|
||||
if (buf[0] != FRAME_HEADER_H || buf[1] != FRAME_HEADER_L)
|
||||
{
|
||||
// 验证帧头
|
||||
if (buf[0] != FRAME_HEADER_H || buf[1] != FRAME_HEADER_L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 获取数据长度(大端模式)
|
||||
uint16_t data_len = buf[4];
|
||||
|
||||
// 检查总长度是否合法
|
||||
if (data_len > 256 || len < (data_len + 6))
|
||||
{
|
||||
// 验证数据长度合法性
|
||||
if (data_len > 256 || len < (data_len + 6)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 计算校验和(从帧头到数据区的所有字节)
|
||||
uint8_t sum = 0;
|
||||
sum = xu316_calc_checksum(buf, data_len + 5);
|
||||
|
||||
// 检查校验和
|
||||
if (sum != buf[data_len + 5])
|
||||
{
|
||||
// 计算并验证校验和
|
||||
uint8_t sum = xu316_calc_checksum(buf, data_len + 5);
|
||||
if (sum != buf[data_len + 5]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -276,72 +258,67 @@ uint8_t uart_frame_check(uint8_t *buf, uint8_t len)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
**封装数据帧**
|
||||
|
||||
```
|
||||
### 5.2 数据帧封装
|
||||
```c
|
||||
int xu316_pack_frame(uint8_t cmd, uint8_t *data, uint8_t len)
|
||||
{
|
||||
uint8_t tx_data[256] = {0};
|
||||
if (len >= 255)
|
||||
if (len >= 255) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 构建帧头
|
||||
tx_data[0] = FRAME_HEADER_H;
|
||||
tx_data[1] = FRAME_HEADER_L;
|
||||
tx_data[2] = PROTOCOL_VERSION_RX;
|
||||
tx_data[3] = cmd;
|
||||
tx_data[4] = len;
|
||||
|
||||
if (data && len > 0)
|
||||
{
|
||||
// 复制数据负载
|
||||
if (data && len > 0) {
|
||||
memcpy(tx_data + 5, data, len);
|
||||
}
|
||||
|
||||
// 计算校验和
|
||||
tx_data[len + 5] = xu316_calc_checksum((uint8_t *)tx_data, len + 5);
|
||||
// 计算并添加校验和
|
||||
tx_data[len + 5] = xu316_calc_checksum(tx_data, len + 5);
|
||||
len += 6;
|
||||
|
||||
// 发送数据
|
||||
usart_dma_send(tx_data, len);
|
||||
LOG_INFO("Sending frame: cmd=0x%02X, len=%d", cmd, len);
|
||||
LOG_TEMP(LOG_SEND, "", tx_data, len);
|
||||
return len; // 返回总帧长度
|
||||
|
||||
return len;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
**检查帧的完整性并返回帧长度**
|
||||
|
||||
```
|
||||
### 5.3 帧长度检查
|
||||
```c
|
||||
int check_frame_length(uint8_t *buf, uint16_t len) {
|
||||
|
||||
// 检查帧头
|
||||
// 验证帧头
|
||||
if (buf[0] != FRAME_HEADER_H || buf[1] != FRAME_HEADER_L) {
|
||||
LOG_DEBUG("Frame header check failed %02x %02x", buf[0], buf[1]);
|
||||
return -1;
|
||||
}
|
||||
// 获取数据长度(大端模式)
|
||||
int data_len = buf[4];
|
||||
|
||||
// 返回完整帧的长度
|
||||
// 返回完整帧长度
|
||||
return data_len + 6;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
```
|
||||
### 5.4 数据接收处理
|
||||
```c
|
||||
void uart_data_process(void)
|
||||
{
|
||||
uint8_t peek_buffer[8]; // 用于预读的缓冲区
|
||||
uint8_t process_buffer[256]; // 处理缓冲区
|
||||
uint8_t peek_buffer[8]; // 预读缓冲区
|
||||
uint8_t process_buffer[256]; // 处理缓冲区
|
||||
int frame_length;
|
||||
|
||||
while(uart_ring_buffer.count >= 6) { // 至少需要6字节才能开始检查
|
||||
|
||||
// 预读帧头信息
|
||||
ring_buffer_peek(peek_buffer, 6);
|
||||
|
||||
|
||||
// 调试输出
|
||||
for(int i = 0; i < 6; i++) {
|
||||
LOG_DEBUG("peek_buffer[%d]: %02x", i, peek_buffer[i]);
|
||||
}
|
||||
@@ -362,7 +339,7 @@ void uart_data_process(void)
|
||||
break; // 等待更多数据
|
||||
}
|
||||
|
||||
// 读取完整帧
|
||||
// 读取并处理完整帧
|
||||
if(ring_buffer_read(process_buffer, frame_length)) {
|
||||
uart_data_parse();
|
||||
}
|
||||
@@ -370,11 +347,8 @@ void uart_data_process(void)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
**数据解析**
|
||||
|
||||
```
|
||||
### 5.5 数据解析处理
|
||||
```c
|
||||
int uart_data_parse(void)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -385,205 +359,49 @@ int uart_data_parse(void)
|
||||
static uint8_t buffer[256] = {0};
|
||||
rx_len = g_rx_count;
|
||||
|
||||
// 验证帧完整性
|
||||
ret = uart_frame_check((uint8_t *)g_rx_data, rx_len);
|
||||
if (ret == 0)
|
||||
{
|
||||
if (ret == 0) {
|
||||
LOG_ERROR("Frame check failed %d", rx_len);
|
||||
LOG_TEMP(LOG_RECV, "", g_rx_data, rx_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 解析帧信息
|
||||
data_len = rx_len - 6;
|
||||
cmd = g_rx_data[3];
|
||||
if (g_rx_data[4] != data_len)
|
||||
{
|
||||
if (g_rx_data[4] != data_len) {
|
||||
LOG_ERROR("Data length mismatch: expected %d, got %d", g_rx_data[4], data_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_DEBUG("Received frame: cmd=0x%02X, len=%d", cmd, data_len);
|
||||
LOG_VERBOSE("--------------------------------");
|
||||
LOG_VERBOSE("cmd : %02X", cmd);
|
||||
memcpy(buffer, g_rx_data + 5, data_len);
|
||||
```
|
||||
|
||||
|
||||
|
||||
```
|
||||
switch (cmd)
|
||||
{
|
||||
case 0x00:
|
||||
{
|
||||
LOG_INFO("Processing boot info");
|
||||
LOG_VERBOSE("boot_info->reboot_reason: %02X", buffer[0]);
|
||||
LOG_VERBOSE("boot_info->vid_uac1: %02X%02X", buffer[1], buffer[2]);
|
||||
LOG_VERBOSE("boot_info->pid_uac1: %02X%02X", buffer[3], buffer[4]);
|
||||
LOG_VERBOSE("boot_info->vid_uac2: %02X%02X", buffer[5], buffer[6]);
|
||||
LOG_VERBOSE("boot_info->pid_uac2: %02X%02X", buffer[7], buffer[8]);
|
||||
LOG_VERBOSE("boot_info->basic_info_crc: %02X%02X%02X%02X", buffer[9], buffer[10], buffer[11], buffer[12]);
|
||||
LOG_VERBOSE("boot_info->power_cfg_crc: %02X%02X%02X%02X", buffer[13], buffer[14], buffer[15], buffer[16]);
|
||||
mcu_data.boot_option = 0;
|
||||
|
||||
if (memcmp(buffer + 9, mcu_data.basic_info_crc, 4) != 0)
|
||||
{
|
||||
mcu_data.boot_option |= BOOT_OPTION_UPDATE_BASIC_INFO;
|
||||
}
|
||||
if (memcmp(buffer + 13, mcu_data.power_cfg_crc, 4) != 0)
|
||||
{
|
||||
mcu_data.boot_option |= BOOT_OPTION_UPDATE_POWER_CFG;
|
||||
}
|
||||
ret = xu316_pack_frame(cmd, &mcu_data.boot_option, CMD00_MCU_DATA_LEN);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x01:
|
||||
{
|
||||
LOG_VERBOSE("Haven't received any data");
|
||||
crc = calculate_crc32(mcu_data.vid_uac1, 56);
|
||||
mcu_data.basic_info_crc[0] = (crc >> 24) & 0xFF;
|
||||
mcu_data.basic_info_crc[1] = (crc >> 16) & 0xFF;
|
||||
mcu_data.basic_info_crc[2] = (crc >> 8) & 0xFF;
|
||||
mcu_data.basic_info_crc[3] = crc & 0xFF;
|
||||
ret = xu316_pack_frame(cmd, mcu_data.vid_uac1, CMD01_MCU_DATA_LEN);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x02:
|
||||
{
|
||||
LOG_VERBOSE("Haven't received any data");
|
||||
crc = calculate_crc32((uint8_t *)&mcu_data.audio_mode, 0x0a);
|
||||
mcu_data.power_cfg_crc[0] = (crc >> 24) & 0xFF;
|
||||
mcu_data.power_cfg_crc[1] = (crc >> 16) & 0xFF;
|
||||
mcu_data.power_cfg_crc[2] = (crc >> 8) & 0xFF;
|
||||
mcu_data.power_cfg_crc[3] = crc & 0xFF;
|
||||
ret = xu316_pack_frame(cmd, (uint8_t *)&mcu_data.audio_mode, CMD02_MCU_DATA_LEN);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x03:
|
||||
{
|
||||
LOG_VERBOSE("Haven't received any data");
|
||||
ret = xu316_pack_frame(cmd, (uint8_t *)&mcu_data.audio_mode, CMD03_MCU_DATA_LEN);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x04:
|
||||
{
|
||||
LOG_VERBOSE("Haven't received any data");
|
||||
memcpy((uint8_t *)&mcu_data.audio_mode, (uint8_t *)audio_modes[g_current_mode], 5);
|
||||
crc = calculate_crc32((uint8_t *)&mcu_data.audio_mode, 10);
|
||||
memcpy(buffer, &mcu_data.audio_mode, 10);
|
||||
mcu_data.power_cfg_crc[0] = (crc >> 24) & 0xFF;
|
||||
mcu_data.power_cfg_crc[1] = (crc >> 16) & 0xFF;
|
||||
mcu_data.power_cfg_crc[2] = (crc >> 8) & 0xFF;
|
||||
mcu_data.power_cfg_crc[3] = crc & 0xFF;
|
||||
ret = xu316_pack_frame(cmd, (uint8_t *)&mcu_data.audio_mode, CMD04_MCU_DATA_LEN);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x05:
|
||||
{
|
||||
LOG_VERBOSE("Haven't received any data");
|
||||
memcpy(&mcu_data.startup_status, buffer, 15);
|
||||
LOG_VERBOSE("audio_mode.startup_status: %02X", mcu_data.startup_status);
|
||||
LOG_VERBOSE("audio_mode.mode: %02X%02X%02X%02X%02X", mcu_data.audio_mode[0], mcu_data.audio_mode[1], mcu_data.audio_mode[2], mcu_data.audio_mode[3], mcu_data.audio_mode[4]);
|
||||
LOG_VERBOSE("audio_mode.mute_duration: %02X%02X", mcu_data.mute_duration[0], mcu_data.mute_duration[1]);
|
||||
LOG_VERBOSE("audio_mode.mic_volume: %02X", mcu_data.mic_volume);
|
||||
LOG_VERBOSE("audio_mode.dac_l_volume: %02X", mcu_data.dac_l_volume);
|
||||
LOG_VERBOSE("audio_mode.dac_r_volume: %02X", mcu_data.dac_r_volume);
|
||||
LOG_VERBOSE("audio_mode.power_cfg_crc: %02X%02X%02X%02X", mcu_data.power_cfg_crc[0], mcu_data.power_cfg_crc[1], mcu_data.power_cfg_crc[2], mcu_data.power_cfg_crc[3]);
|
||||
ret = xu316_pack_frame(cmd, NULL, CMD05_MCU_DATA_LEN);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x20:
|
||||
{
|
||||
memcpy(&mcu_data.audio_mode, buffer, 14);
|
||||
LOG_VERBOSE("audio_mode.mode: %02X%02X%02X%02X%02X", mcu_data.audio_mode[0], mcu_data.audio_mode[1], mcu_data.audio_mode[2], mcu_data.audio_mode[3], mcu_data.audio_mode[4]);
|
||||
LOG_VERBOSE("audio_mode.mute_duration: %02X%02X", mcu_data.mute_duration[0], mcu_data.mute_duration[1]);
|
||||
LOG_VERBOSE("audio_mode.mic_volume: %02X", mcu_data.mic_volume);
|
||||
LOG_VERBOSE("audio_mode.dac_l_volume: %02X", mcu_data.dac_l_volume);
|
||||
LOG_VERBOSE("audio_mode.dac_r_volume: %02X", mcu_data.dac_r_volume);
|
||||
LOG_VERBOSE("audio_mode.power_cfg_crc: %02X%02X%02X%02X", mcu_data.power_cfg_crc[0], mcu_data.power_cfg_crc[1], mcu_data.power_cfg_crc[2], mcu_data.power_cfg_crc[3]);
|
||||
ret = xu316_pack_frame(cmd, NULL, CMD20_MCU_DATA_LEN);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x22:
|
||||
{
|
||||
memcpy(&mcu_data.audio_format, buffer, 2);
|
||||
LOG_VERBOSE("audio_mode.audio_format: %02X", mcu_data.audio_format);
|
||||
LOG_VERBOSE("audio_mode.audio_type: %02X", mcu_data.audio_type);
|
||||
ret = xu316_pack_frame(cmd, NULL, CMD22_MCU_DATA_LEN);
|
||||
break;
|
||||
}
|
||||
case 0x24:
|
||||
{ // 发送播放音量
|
||||
memcpy(&mcu_data.dac_l_volume, buffer, 2);
|
||||
LOG_VERBOSE("audio_mode.dac_l_volume: %02X", mcu_data.dac_l_volume);
|
||||
LOG_VERBOSE("audio_mode.dac_r_volume: %02X", mcu_data.dac_r_volume);
|
||||
ret = xu316_pack_frame(cmd, NULL, CMD24_MCU_DATA_LEN);
|
||||
break;
|
||||
}
|
||||
case 0x25:
|
||||
{ // 发送录音音量, 预留
|
||||
LOG_VERBOSE("audio_mode.mic_volume: %02X", mcu_data.mic_volume);
|
||||
ret = xu316_pack_frame(cmd, NULL, CMD25_MCU_DATA_LEN);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x27: // 处理 unmute 命令的响应 (0x27)
|
||||
{
|
||||
// g_rx_data[2] 是接收到的版本号, g_rx_data[4] 是接收到的数据长度
|
||||
if (g_rx_data[2] == 0x00 && g_rx_data[4] == CMD27_XU316_DATA_LEN) // XU316 返回的版本号应为 0x00, 数据长度应为 0
|
||||
{
|
||||
LOG_INFO("0x27 (Unmute) response received successfully.");
|
||||
// unmute 成功,可以在这里添加其他逻辑,例如更新设备状态
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("0x27 (Unmute) response error: version 0x%02X, len %d", g_rx_data[2], g_rx_data[4]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x28: // 处理设置音频格式时间延迟命令的响应 (0x28)
|
||||
{
|
||||
if (g_rx_data[2] == 0x00 && g_rx_data[4] == CMD28_XU316_DATA_LEN) // XU316 返回的版本号应为 0x00, 数据长度应为 0
|
||||
{
|
||||
LOG_INFO("0x28 (Set Audio Format Delay) response received successfully.");
|
||||
// 可以在这里添加其他逻辑
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("0x28 (Set Audio Format Delay) response error: version 0x%02X, len %d", g_rx_data[2], g_rx_data[4]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xEE: // HID/OTA (0xEE) - 简单响应,暂不处理升级
|
||||
{
|
||||
// XU316 发送给 MCU: 版本号 0x00, 数据长度 0x39 (57)
|
||||
// MCU 回复 XU316: 版本号 0x03, 数据长度 0x39 (57)
|
||||
if (g_rx_data[2] == 0x00 && g_rx_data[4] == CMD_HID_TRANSPARENT_DATA_LEN)
|
||||
{
|
||||
LOG_INFO("Received 0xEE (HID/OTA) from XU316: version=0x%02X, data_len=%d", g_rx_data[2], g_rx_data[4]);
|
||||
|
||||
// 简单回复接收到的数据(echo模式)
|
||||
xu316_pack_frame(0xEE, buffer, CMD_HID_TRANSPARENT_MCU_DATA_LEN);
|
||||
LOG_INFO("Sent 0xEE (HID/OTA) response to XU316.");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("0xEE (HID/OTA) packet error from XU316: expected version 0x00 and data_len %d (0x%02X), "
|
||||
"but got version 0x%02X and data_len %d (0x%02X)",
|
||||
CMD_HID_TRANSPARENT_DATA_LEN, CMD_HID_TRANSPARENT_DATA_LEN,
|
||||
g_rx_data[2], g_rx_data[4], g_rx_data[4]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: // 未知命令处理
|
||||
LOG_ERROR("Unknown command: 0x%02X", cmd);
|
||||
break;
|
||||
|
||||
// 根据命令类型处理数据
|
||||
switch (cmd) {
|
||||
case 0x00: // 启动信息
|
||||
// ... 处理启动信息 ...
|
||||
break;
|
||||
|
||||
case 0x01: // 基础信息
|
||||
// ... 处理基础信息 ...
|
||||
break;
|
||||
|
||||
case 0x02: // 电源配置
|
||||
// ... 处理电源配置 ...
|
||||
break;
|
||||
|
||||
// ... 其他命令处理 ...
|
||||
|
||||
default:
|
||||
LOG_ERROR("Unknown command: 0x%02X", cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -267,6 +267,10 @@ nav:
|
||||
- XU316 USB HiFi解码器免开发产品配置协议: dev_doc/protocols/xu316_zerocode_protocol.md
|
||||
- 开发SDK与示例:
|
||||
- dev_doc/sdk_examples/index.md
|
||||
- A316免开发固件开发示例:
|
||||
- XU316音频接口控制代码示例: dev_doc/sdk_examples/XU316和MCU通讯的示例代码/产品内容相关.md
|
||||
- XU316与MCU通信协议命令宏定义: dev_doc/sdk_examples/XU316和MCU通讯的示例代码/命令相关宏.md
|
||||
- XU316与MCU通信协议参考: dev_doc/sdk_examples/XU316和MCU通讯的示例代码/命令相关.md
|
||||
# - 5.1标准固件使用示例:
|
||||
# - 8711开发板连接说明: dev_doc/hifi_audio/a316_1926v1/RTL8711dome.md
|
||||
# - 开发板硬件连接说明: dev_doc/hifi_audio/a316_1926v1/A316-8711-5.1解码无线音频套装制作说明.md
|
||||
|
||||
Reference in New Issue
Block a user