1173363_zh-CN

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

1173363_zh-CN

1173363_zh-CN

在 Kinetis K32L2B 上使用 DMA 进行多 ADC 通道分配和结果读取

简介

问题陈述:K32L2B ADC 无法在一次转换中扫描所有连接的通道。输入通道被复用到 ADC 中,因此您需要将 ADCx_Rn 寄存器设置为要转换的通道号,运行转换,读取结果,然后将该 ADC 中的另一个 ADCx_Rn 设置为下一个要转换的通道。然后可以触发下一次转换。您必须告诉每个转换要转换的输入通道。每次设置新频道并读取先前频道的数据都会消耗大量的CPU核心带宽。

本示例的目标是连续读取 Kinetis K32L2B 的所有 ADC 输入,而无需使用 CPU 内核切换通道和读取单个结果值。

项目描述

本例中的DMA用于控制所有通道的切换,将一系列测量的结果读入内存缓冲区。

直接内存访问 (DMA) 通道配置为按以下方式写入和读取 ADC 寄存器:

  • DMA 通道 0 读取转换结果(ADC0_RA 寄存器)并将其存储在 g_adc16SampleDataArray[ ] 中。
  • DMA 通道 1 选择 ADC 通道并使用内存 g_adc16ChannelDataArray[ ] 中的值开始转换(ADC0_SC1A 寄存器)

 

DMA 通道 1 的数据在g_adc16ChannelDataArray中准备 在记忆中准备, DMA 的工作周期如下:

步骤 1首先,使用软件触发启动 DMA 通道 1 传输。这将配置通道并开始转换。

步骤2转换完成后,通过DMA通道0读取结果并存储到结果数组中。通道链接执行通道 1 传输并继续循环。

 测量完所有需要的通道(DMA 字节计数器达到 0)后,将调用 DMA 中断,以便通知用户代码。

参见下图描述该过程:

Capture1.PNGCapture1.PNG

 
 
 
 
 

驱动程序配置

1. ADC初始化(ADC16_配置)

  • 分辨率为16位
  • 单步转换
  • 软件触发
  • 在 COCO=1 时启用 DMA(转换完成)

代码:

static void ADC16_Configuration(void)
{
// adc16_config_t adcUserConfig;


ADC16_获取默认配置(&adcUserConfig);
adcUserConfig.分辨率=kADC16_分辨率16位;
adcUserConfig.enableContinuousConversion=假;
adcUserConfig.clockSource = kADC16_ClockSourceAlt0;

adcUserConfig.enableAsynchronousClock = false;
adcUserConfig.clockDivider=kADC16_ClockDivider2;

adcUserConfig.长采样模式 = kADC16_LongSampleCycle24;
adcUserConfig.enableLowPower=假;
#if ((定义BOARD_ADC_USE_ALT_VREF) && BOARD_ADC_USE_ALT_VREF)
adcUserConfig.参考电压源= kADC16_ReferenceVoltageSourceValt;
#结束
ADC16_Init(DEMO_ADC16_BASEADDR, &adcUserConfig);
ADC16_设置硬件平均值(DEMO_ADC16_BASEADDR,kADC16_HardwareAverageCount4);


/* 配置 SIM 以选择 ADC 硬件触发源 */
// SIM->SOPT7 |= 0x8EU;

#如果定义(FSL_FEATURE_ADC16_HAS_CALIBRATION)&& FSL_FEATURE_ADC16_HAS_CALIBRATION
/* 自动校准 */
如果(kStatus_Success == ADC16_DoAutoCalibration(DEMO_ADC16_BASEADDR))
{
PRINTF("ADC16_DoAutoCalibration() 完成.\r\n");
}
别的
{
PRINTF("ADC16_DoAutoCalibration()失败.\r\n");
}
#结束

/* 启用软件触发。*/
ADC16_启用硬件触发器(DEMO_ADC16_BASEADDR,false);
/* 启用 DMA。*/
ADC16_EnableDMA(DEMO_ADC16_BASEADDR,真);

}

2. DMA 通道0(DMA_config_ch_0())

  • 32 位结果从 ADC0_RA 寄存器传输(见属性 数据源/地址)。
  • 传输模式为循环窃取 (Cycle-steal),这意味着每个外部请求只进行一次交易。
  • 通道链接设置为在每次传输后触发通道 1
  • 通道 0 的 DMA mux 设置已启用,并选择 ADC0_DMA_Request,这是转换结束时来自 ADC 的信号。
  • 启用外部请求(来自 ADC 的请求)来启动传输。字节数也会在每个序列之前改变
  • 每次传输后目标地址自动增加,以指向 adc 结果数组(PeripheraltoMemory)中的下一个索引

3. DMA 通道1(DMA_config_ch_1())

  • DMA 通道 1 选择 ADC 通道并使用存储器阵列 g_adc16ChannelDataArray[n] 中的值开始转换(ADC0_SC1A 寄存器)
  • 一次传输8位数据。
  • 源地址自动增加以指向数组中的下一个索引。
  • 传输结束后,没有链接任何频道。
  • 未选择外部通道请求,此通道传输由来自 CH0 的链接触发。

代码:

void get_DMA_Channel_link(dma_channel_link_config_t *config)
{
配置->链接类型 = 2;
配置->通道1 = 1;
}


静态无效DMA_config_ch_0()
{
DMA_CreateHandle(&g_DMA_Handle,DEMO_DMA_BASEADDR,DEMO_DMA_CHANNEL);
DMA_SetCallback(&g_DMA_Handle,DMA_Callback,NULL);
DMA_PrepareTransfer(&g_transferConfig,(void *)ADC16_RESULT_REG_ADDR,sizeof(uint32_t),
&g_adc16SampleDataArray[0],sizeof(uint32_t),20,
kDMA_外设到内存);
DMA_SubmitTransfer(&g_DMA_Handle,&g_transferConfig,kDMA_EnableInterrupt);
获取DMA通道链接(&通道链接);
DMA_SetChannelLinkConfig(g_DMA_Handle.base,0,&channel_link);
}

静态void DMA_config_ch_1()
{
DMA_CreateHandle(&g_DMA_Handle_channel_1,DEMO_DMA_BASEADDR,1);
// DMA_SetCallback(&g_DMA_Handle_channel_1,DMA_Callback_channel_1,NULL);
DMA_PrepareTransfer(&g_transferConfig_channel_1,&g_adc16ChannelDataArray[0],sizeof(uint8_t),
(void *)通道地址,sizeof(uint8_t),5,
kDMA_内存到外设);
DMA_SubmitTransfer(&g_DMA_Handle_channel_1,&g_transferConfig_channel_1,kDMA_NoOptions);
DMA_TriggerChannelStart(g_DMA_Handle_channel_1.base,1);
}

4. 运行演示

  • 将附件项目导入 MCUXpresso v11.2、SDK v2.8.0 K32L2B
  • 构建项目
  • 将 FRDM K32L2B 开发板连接至 PC
  • 调试并运行应用程序
  • 在全局变量窗口中观察 g_adc16SampleDataArray[n] 中 ADC 结果,分别针对 g_adc16ChannelDataArray[n]中给出的通道 SC1A 数据

Capture.PNGCapture.PNG

附件是供参考的项目。

如果需要任何其他信息,请告诉我。

谢谢!!

Tags (1)
No ratings
Version history
Last update:
‎01-06-2026 12:55 AM
Updated by: