GD32H737 1Mbps 数字通信链路实现

一、项目概述

本项目基于 GD32H737VMT6 单片机,利用片上定时器、DMA、GPIO 外设,实现一套完整的数字信号收发与同步解调链路。无需专用通信芯片,仅通过软件算法完成高速率、高可靠性的通信验证,可直接应用于自定义串口、无线基带、高速数据传输等场景。

核心功能

  • 1Mbps 码率数字波形发送
  • 5MHz 硬件过采样接收
  • DMA 乒乓缓冲,采样与处理并行执行
  • 位同步(DTTL)自动校正时钟偏差
  • 帧同步(前导码检测)实现帧数据对齐
  • 误码率自动统计,实测 0 误码稳定传输

二、整体工作逻辑

1. 信号发送逻辑

  1. 定义待发送字节数据,将其按位展开为比特流
  2. 构建 DMA 发送缓冲区,每一位对应 GPIO 置 1 或清 0 操作
  3. 定时器 1 以 1Mbps 频率触发 DMA 请求
  4. DMA 直接将波形数据搬运至 GPIO 输出,全程不占用 CPU

2. 信号接收与乒乓缓冲逻辑

  1. 定时器 2 以 5MHz 频率对输入信号进行采样
  2. DMA 持续将采样值搬运至接收缓冲区
  3. 接收缓冲区分为前半段、后半段,形成乒乓结构
  4. 半满中断触发:处理前半段采样数据
  5. 全满中断触发:处理后半段采样数据
  6. 采样与解调并行执行,无数据丢失、无覆盖

3. 解调与同步逻辑

  1. 将采样值归一化为判决电平,便于比特识别
  2. 位同步:动态调整采样点,保证每一位采样位置准确
  3. 帧同步:匹配预设前导码,定位有效数据起始位置
  4. 按字节重组数据,完成帧解包
  5. 与原始发送数据对比,统计总比特数、错误比特数,计算误码率

三、核心模块实现逻辑

1. DMA 乒乓操作

乒乓缓冲是保证 1Mbps 速率下不丢采样点的关键机制。DMA 填充缓冲区时,CPU 可处理另一半区域数据,实现采样与处理并行。

  • 半传输完成中断:标记前半段缓冲区就绪

  • 全传输完成中断:标记后半段缓冲区就绪

  • 中断服务函数仅做标志位处理,无耗时运算

    void DMA1_Channel2_IRQHandler(void)
    {
    // 半传输完成
    if(dma_interrupt_flag_get(DMA1, DMA_CH2, DMA_INT_FLAG_HTF))
    {
    dma_interrupt_flag_clear(DMA1, DMA_CH2, DMA_INT_FLAG_HTF);
    rx_half_collision = processing_flag;
    rx_half_flag = 1;
    }
    // 全传输完成
    if(dma_interrupt_flag_get(DMA1, DMA_CH2, DMA_INT_FLAG_FTF))
    {
    dma_interrupt_flag_clear(DMA1, DMA_CH2, DMA_INT_FLAG_FTF);
    rx_full_collision = processing_flag;
    rx_full_flag = 1;
    }
    }

主循环根据中断标志处理对应缓冲区:

复制代码
if(rx_half_flag)
{
    processing_flag = 1;
    rx_half_flag = 0; 
    process_rx_data(dma_rx_buf, SAMPLE_COUNT/2, 1);
    processing_flag = 0;
}
else if(rx_full_flag)
{
    processing_flag = 1;
    rx_full_flag = 0;
    process_rx_data(&dma_rx_buf[SAMPLE_COUNT/2], SAMPLE_COUNT/2, 2);
    processing_flag = 0;	
}

2. 位同步逻辑

位同步用于消除收发时钟偏差带来的采样错位,是实现 0 误码的核心。通过 PID 控制器动态调整采样步长,锁定最佳采样时刻。

  1. 对采样数据分块取平均,完成比特判决

  2. 检测比特边沿跳变,计算采样位置误差

  3. 动态修正采样时钟,保证每一位采样稳定可靠

    复制代码
     	// ===================== 位同步 + 比特判决(ARM_MATH加速) =====================
     	for (int sym = 0; sym < total_symbols; sym++)
     	{
     		float step = sps * sync_feed;
    
     		if ((int32_t)start_idx >= input_len) {
     			new_bit = 0;
     			bits[sym] = new_bit;
     			continue;
     		}
    
     		int32_t block_start = (int32_t)roundf(start_idx);
     		int32_t block_size  = (int32_t)step;
     		if (block_start + block_size > input_len) {
     			block_size = input_len - block_start;
     		}
     		if (block_size <= 0) {
     			new_bit = 0;
     			bits[sym] = new_bit;
     			continue;
     		}
    
     		// ===== 核心加速:arm_mean_q7(这个函数一定存在)=====
     		q7_t mean_val;
     		arm_mean_q7(&input[block_start], block_size, &mean_val);
    
     		new_bit = (mean_val < 0) ? 0 : 1;
     		bits[sym] = new_bit;
     		
     		// ===== 边沿检测 + PID =====
     		if (new_bit != old_bit && start_idx > 2 * sps)
     		{
     			float half_sps = step / 2.0f;
     			int32_t sum_start = (int32_t)roundf(start_idx - half_sps);
     			int32_t sum_len   = (int32_t)roundf(sps);
    
     			if (sum_start < 0) sum_start = 0;
     			if (sum_start + sum_len > input_len) {
     				sum_len = input_len - sum_start;
     			}
     			
     			// ===== 修复:替换为安全求和 =====
     			q7_t sum_val = 0;
     			for(int k=0; k<sum_len; k++){
     				sum_val += input[sum_start + k];
     				
     			}
     	  	
     			float err = (new_bit == 1) ? -(float)sum_val : (float)sum_val;
     			float p = kp * err;
     			integral += err;
     			float i = ki * integral;
    
     			sync_feed = 1.0f + p + i;
    
     			if (sync_feed < 0.7f || sync_feed > 1.3f) {
     				sync_feed = 1.0f;
     				integral = 0.0f;
     			}

    // printf("%f,", step);
    }

    复制代码
     		old_bit = new_bit;
     		start_idx += step;
     	}

3. 帧同步逻辑

位同步保证单比特正确,帧同步用于确定一帧数据的起始位置,避免帧错位。

  1. 预设 16bit 固定前导码

  2. 在解调比特流中逐位匹配前导码

  3. 匹配成功后,从当前位置开始解包有效数据

    int preamble_pos = -1;
    for (int i = 0; i <= total_symbols - PREAMBLE_LENGTH; i++)
    {
    int match = 1;
    for (int j = 0; j < PREAMBLE_LENGTH; j++)
    {
    if (bits[i + j] != FSK_PREAMBLE[j])
    {
    match = 0;
    break;
    }
    }
    if (match)
    {
    preamble_pos = i;
    break;
    }
    }


4. 1Mbps 速率配置逻辑

系统主频 300MHz,通过定时器周期精准控制发送与采样频率:

  • 发送码率:1Mbps

  • 接收采样率:5MHz(5 倍过采样)

  • 定时器无分频,直接由主频驱动,时序精度高

    #define SYSTEM_CLOCK 300000000U
    #define TX_BAUD_RATE 1000000U
    #define TIMER_TX_PERIOD (SYSTEM_CLOCK / TX_BAUD_RATE - 1U)

    #define RX_SAMPLE_RATE 5000000U
    #define TIMER_RX_PERIOD (SYSTEM_CLOCK / RX_SAMPLE_RATE - 1U)


5. 误码率统计逻辑

通过逐位对比发送数据与接收数据,统计通信可靠性:

  1. 按字节异或,判断比特是否错误

  2. 累计总传输比特数与错误比特数

  3. 误码率 = 错误比特数 / 总比特数

    void calculate_ber(const uint8_t *tx_bytes, uint32_t tx_len,
    const uint8_t *rx_bytes, uint32_t rx_len)
    {
    uint32_t compare_len = rx_len;
    if (compare_len == 0) return;

    复制代码
     for (uint32_t i = 0; i < compare_len - 1; i++)
     {
         uint8_t tx = tx_bytes[i % TX_DATA_LEN];
         uint8_t rx = rx_bytes[i];
         uint8_t xor_val = tx ^ rx;
         ber_stat.total_bits += 8;
    
         for (int j = 0; j < 8; j++)
         {
             if (xor_val & (1 << j))
                 ber_stat.error_bits++;
         }
     }

    }


四、测试结果

程序完成 100 次收发测试后,串口输出误码率统计:

plaintext

复制代码
[BER统计] 总比特:102400  错误:0  误码率:0.000000

在 1Mbps 码率下,实现连续稳定的 0 误码通信。


五、适用场景

  • 自定义高速数字通信接口
  • 软件无线电基带信号处理
  • 无线模块数字解调
  • 工业高速数据传输
  • 通信原理教学与实验
相关推荐
归零鸟14 小时前
WD Elements移动硬盘能识别出盘但不能出盘的修复记录
stm32·单片机·嵌入式硬件
追兮兮15 小时前
MCUQuickStart v1.1.0发布,一键生成Keil工程+RTOS模板
stm32·单片机·嵌入式硬件·freertos·gd32·keil5
国科安芯15 小时前
ASP7A84AS与主流架构兼容替代及系统级电源完整性解决方案的深度研究
单片机·嵌入式硬件·架构
kaikaile199515 小时前
STC8单片机实现简单花样DMX512控制器
单片机·嵌入式硬件
rit843249915 小时前
STM32移植NES模拟器指南
stm32·单片机·嵌入式硬件
fengfuyao98516 小时前
STM32 HAL库实现串口DMA接收不定长数据
stm32·单片机·嵌入式硬件
yuan1999716 小时前
STM32直流无刷电机六拍方波控制器程序
stm32·单片机·嵌入式硬件
番茄灭世神17 小时前
PN学堂GD32教程第21篇——WiFiIOT
c语言·stm32·单片机·嵌入式·gd32
jghhh0118 小时前
基于DSP28335的RS485串口通信与AD采样开发方案
单片机·嵌入式硬件