diff --git a/zh/docs/dev_doc/sdk_examples/XU316和MCU通讯的示例代码/产品内容相关.md b/zh/docs/dev_doc/sdk_examples/XU316和MCU通讯的示例代码/产品内容相关.md index 00e01e9..bb54c4d 100644 --- a/zh/docs/dev_doc/sdk_examples/XU316和MCU通讯的示例代码/产品内容相关.md +++ b/zh/docs/dev_doc/sdk_examples/XU316和MCU通讯的示例代码/产品内容相关.md @@ -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 +``` + + + ``` + diff --git a/zh/docs/dev_doc/sdk_examples/XU316和MCU通讯的示例代码/命令的相关宏.md b/zh/docs/dev_doc/sdk_examples/XU316和MCU通讯的示例代码/命令的相关宏.md index 69eb964..4b5d79f 100644 --- a/zh/docs/dev_doc/sdk_examples/XU316和MCU通讯的示例代码/命令的相关宏.md +++ b/zh/docs/dev_doc/sdk_examples/XU316和MCU通讯的示例代码/命令的相关宏.md @@ -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; ``` + + diff --git a/zh/docs/dev_doc/sdk_examples/XU316和MCU通讯的示例代码/命令相关.md b/zh/docs/dev_doc/sdk_examples/XU316和MCU通讯的示例代码/命令相关.md index d2f64de..d5ebf2a 100644 --- a/zh/docs/dev_doc/sdk_examples/XU316和MCU通讯的示例代码/命令相关.md +++ b/zh/docs/dev_doc/sdk_examples/XU316和MCU通讯的示例代码/命令相关.md @@ -1,31 +1,42 @@ -**命令相关** +--- +title: XU316与MCU通信协议参考 +description: XU316与MCU之间的通信协议详细说明,包括数据结构、命令格式和处理流程 +keywords: XU316, MCU, 通信协议, 命令参考 +hide: + -toc +--- + -``` -#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; +} ``` diff --git a/zh/mkdocs.yml b/zh/mkdocs.yml index fdbf310..967fe1b 100644 --- a/zh/mkdocs.yml +++ b/zh/mkdocs.yml @@ -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