1. 问题现象与背景分析
最近在调试GD32E230系列MCU时发现一个奇怪现象:当程序执行Flash擦写操作时,ADC采集的数据会出现明显的位错乱。具体表现为原本稳定的12位ADC读数突然出现高位或低位偏移,导致采样值异常波动。这个问题在电池电压监测、温度采集等对ADC精度要求较高的场景中尤为致命。
GD32E230作为一款Cortex-M23内核的MCU,Flash和ADC都属于关键外设。根据我的实测数据,在Flash页擦除期间,ADC通道的采样值会出现约8-12LSB的偏移(相当于参考电压的0.2%-0.3%)。这种硬件级的干扰在精密测量场景是完全不可接受的。
2. 根本原因探究
2.1 电源完整性影响
通过示波器捕捉VDD波形发现,Flash操作时电源会出现约50mV的瞬时跌落(持续时间约2μs)。这是因为GD32E230采用单电源设计,Flash擦写时高达20mA的瞬态电流会引发电源噪声。虽然芯片内部有LDO稳压,但ADC的参考电压(通常直接取自VDD)仍会受到牵连。
2.2 时钟同步问题
GD32E230的ADC时钟源默认来自APB总线。当CPU执行Flash操作时,总线时钟可能出现微秒级的抖动。实测显示,此时ADC的采样保持时间会从正常的7个时钟周期缩短到5-6个周期,导致采样电容充电不充分。
2.3 寄存器访问冲突
查阅手册发现,Flash控制器和ADC共用同一个AHB总线矩阵。当Flash执行擦除命令时,会短暂阻塞总线访问。如果此时ADC正在写入数据寄存器,就可能出现部分位写入失败的情况。
3. 解决方案与实测验证
3.1 硬件改进措施
- 在VDD引脚增加100μF钽电容+100nF陶瓷电容组合,将电源跌落控制在10mV以内
- 采用独立基准电压源(如TL431)为ADC_REF供电
- PCB布局时使Flash和ADC供电走线完全分离
3.2 软件规避方案
c复制// ADC采样期间禁用Flash操作
void safe_adc_read(void)
{
__disable_irq();
if(FMC_CTL & FMC_CTL_OBWEN){
fmc_operation_wait(); // 等待当前Flash操作完成
}
adc_regular_data_read();
__enable_irq();
}
// 使用DMA搬运ADC数据
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC_RDATA;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adc_values;
DMA_InitStructure.DMA_BufferSize = 4;
DMA_Init(DMA_CH0, &DMA_InitStructure);
3.3 时序优化技巧
- 将Flash擦写操作放在ADC采样间隔执行
- 配置ADC为连续转换模式,采样率设置为低于100ksps
- 启用ADC的过采样功能(16倍平均)
4. 实测数据对比
| 条件 | ADC噪声(LSB) | 最大偏移(LSB) |
|---|---|---|
| 原始方案 | 8.2 | 23 |
| 仅硬件改进 | 3.1 | 9 |
| 仅软件优化 | 4.7 | 15 |
| 硬件+软件联合方案 | 1.3 | 3 |
5. 经验总结
- 在GD32E230上执行Flash操作时,建议先暂停高精度ADC采样
- 对于12位及以上ADC,必须使用独立参考电压源
- DMA传输能有效降低总线冲突风险
- 过采样技术可以平滑突发干扰
- 关键时序操作需要配合__disable_irq()使用
这个案例提醒我们,在资源受限型MCU上需要特别注意外设间的相互影响。通过示波器电源纹波测量和逻辑分析仪抓取总线时序,是排查此类问题的有效手段。
