XU316与MCU通信协议参考
1. 基础数据结构
1.1 环形缓冲区
#define RING_BUFFER_SIZE 256 // 环形缓冲区大小,用于UART通信缓存
typedef struct {
uint8_t buffer[RING_BUFFER_SIZE]; // 数据存储区
volatile uint16_t head; // 写入位置指针
volatile uint16_t tail; // 读取位置指针
volatile uint16_t count; // 当前数据量
} ring_buffer_t;
1.2 音频模式定义
// 音频模式配置数组,每个模式包含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模式
};
// 对应的模式名称数组
static const char *mode_names[] = {
"USB-no-mqa",
"UAC1",
"COAX",
"OPT",
"SPDIF OUT",
"I2S IN",
"HDMI"
};
2. 初始化与配置
2.1 设备初始化信息打印
#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);
// 打印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 环形缓冲区初始化
void ring_buffer_init(void) {
uart_ring_buffer.head = 0; // 初始化写入位置
uart_ring_buffer.tail = 0; // 初始化读取位置
uart_ring_buffer.count = 0; // 初始化数据计数
}
2.3 产品信息初始化
void xu316_init(void)
{
// 默认音频模式配置(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
mcu_data.pid_uac1[0] = 0x00;
mcu_data.pid_uac1[1] = 0x17; // PID = 0x0017
// 配置UAC2.0设备信息
mcu_data.vid_uac2[0] = 0x20;
mcu_data.vid_uac2[1] = 0xB1; // VID = 0x20B1
mcu_data.pid_uac2[0] = 0x00;
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校验值(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);
// 配置静音持续时间(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校验值(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 环形缓冲区操作函数
// 写入数据到环形缓冲区
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; // 写入成功
}
// 从环形缓冲区读取数据
uint8_t ring_buffer_read(uint8_t *data, uint16_t len) {
uint16_t i;
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. 校验和计算
4.1 CRC32计算
uint32_t calculate_crc32(const uint8_t *buffer, uint32_t length)
{
uint32_t crc = 0xFFFFFFFF;
const uint32_t poly = 0xEDB88320; // CRC32多项式
for (size_t i = 0; i < length; i++) {
crc ^= buffer[i];
for (int j = 0; j < 8; j++) {
if (crc & 1) {
crc = (crc >> 1) ^ poly;
} else {
crc >>= 1;
}
}
}
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++) {
sum += data[i];
}
return sum;
}
5. 通信协议处理
5.1 帧校验
// 校验帧数据完整性
uint8_t uart_frame_check(uint8_t *buf, uint8_t len)
{
// 检查最小长度要求
if (len < 6) { // 帧头(2) + 版本(1) + 命令(1) + 长度(2) + 校验(1)
return 0;
}
// 验证帧头
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)) {
return 0;
}
// 计算并验证校验和
uint8_t sum = xu316_calc_checksum(buf, data_len + 5);
if (sum != buf[data_len + 5]) {
return 0;
}
LOG_TEMP(LOG_RECV, "", buf, len);
return 1;
}
5.2 数据帧封装
int xu316_pack_frame(uint8_t cmd, uint8_t *data, uint8_t len)
{
uint8_t tx_data[256] = {0};
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) {
memcpy(tx_data + 5, data, len);
}
// 计算并添加校验和
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;
}
5.3 帧长度检查
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 数据接收处理
void uart_data_process(void)
{
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]);
}
// 检查帧长度
frame_length = check_frame_length(peek_buffer, 6);
if(frame_length < 0) {
// 帧无效,丢弃一个字节
uint8_t dummy;
ring_buffer_read(&dummy, 1);
LOG_ERROR("Frame length check failed %02x", dummy);
continue;
}
// 检查是否有足够的数据
if(uart_ring_buffer.count < frame_length) {
LOG_ERROR("Not enough data");
break; // 等待更多数据
}
// 读取并处理完整帧
if(ring_buffer_read(process_buffer, frame_length)) {
uart_data_parse();
}
}
}
5.5 数据解析处理
int uart_data_parse(void)
{
int ret = 0;
uint8_t cmd = 0;
uint16_t data_len = 0;
uint16_t rx_len = 0;
uint8_t tmp;
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) {
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) {
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: // 启动信息
// ... 处理启动信息 ...
break;
case 0x01: // 基础信息
// ... 处理基础信息 ...
break;
case 0x02: // 电源配置
// ... 处理电源配置 ...
break;
// ... 其他命令处理 ...
default:
LOG_ERROR("Unknown command: 0x%02X", cmd);
break;
}
return ret;
}