TI单片机FIFO MODE的记录
尝试在MSPM0G3507实现6路ADC DMA采样。
TI单片机的ADC DMA与FIFO高度绑定,一开始不了解FIFO,以为只是单纯的先进先出队列,后在使用时发现数据错乱的问题。
翻阅数据手册发现
ADC 的 FIFO 总是将两个样本打包成一个 32 位的 Word 数据。当你读取 FIFODAT 寄存器(无论是 CPU 还是 DMA),你总是会得到一个 32 位的 Word
也就是说DMA读取的FIFO结果不能直接使用,需要处理,分离高16位与低16位。
分离示例
void extract_samples(void)
{
for (int i = 0; i < ADC_FIFO_WORD_COUNT; ++i) {
uint32_t word = gADCWordBuffer[i];
gADCSamples[i * 2] = word & 0xFFFF;
if ((i * 2 + 1) < ADC_CHANNEL_COUNT) {
gADCSamples[i * 2 + 1] = (word >> 16) & 0xFFFF;
}
}
}
另外sysconfig工具中DMA Samples Count比较有迷惑性。官方文档中对 DMA Samples Count 的定义:
Set number of ADC results to be transferred on a DMA trigger.
它不是指“DMA 一次搬运多少数据”,而是:ADC FIFO 每累计 N 个样本,就触发一次 DMA 请求,而不是采完一个完整序列才触发。
实际应用中与adc采样通道数相同即可(其实只要有值就可以)
Transfer Size项才是真真有用的,因为FIFO将两个样本打包成一个 32 位的 Word 数据,所以Transfer Size应该为样本数的一半。一般建议在主程序调用DL_DMA_setTransferSize
实现
全功能示例代码
#include "ti_msp_dl_config.h"
#define ADC_CHANNEL_COUNT 6
#define ADC_FIFO_WORD_COUNT ((ADC_CHANNEL_COUNT + 1) / 2) // 每个Word打包2个样本
volatile uint32_t gADCWordBuffer[ADC_FIFO_WORD_COUNT]; // 每个word包含两个样本
volatile uint16_t gADCSamples[ADC_CHANNEL_COUNT]; // 提取后的样本数组
void extract_samples(void)
{
for (int i = 0; i < ADC_FIFO_WORD_COUNT; ++i) {
uint32_t word = gADCWordBuffer[i];
gADCSamples[i * 2] = word & 0xFFFF;
if ((i * 2 + 1) < ADC_CHANNEL_COUNT) {
gADCSamples[i * 2 + 1] = (word >> 16) & 0xFFFF;
}
}
}
int main(void)
{
SYSCFG_DL_init();
// 设置 DMA
DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) DL_ADC12_getFIFOAddress(ADC12_0_INST));
DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) gADCWordBuffer);
DL_DMA_setTransferSize(DMA, DMA_CH0_CHAN_ID, ADC_FIFO_WORD_COUNT);
// 启用 DMA
DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);
// 启动 ADC 转换
DL_ADC12_startConversion(ADC12_0_INST);
while (1) {
// 每次 DMA 更新完 gADCWordBuffer,手动提取 16位样本
extract_samples();
// 你可以在这里使用 gADCSamples[0..2] 的数据
__NOP(); // 仅用于调试打断点
}
}