This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TM4C123GH6PM:Newbie 需要有关使用 uDMA 设置 ADC 的帮助

Guru**** 1800230 points
Other Parts Discussed in Thread: TM4C123AH6PM, TM4C1294NCPDT
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/647065/tm4c123gh6pm-newbie-needs-help-setting-up-adc-with-udma

器件型号:TM4C123GH6PM
主题中讨论的其他器件:TM4C123TM4C123AH6PMTM4C1294NCPDT

你好。

我在这个论坛上找到了一段代码、用于设置带有 uDMA 的定时器触发 ADC。 链接: e2e.ti.com/.../2025521

我已经阅读了 TivaWare 用户指南、并了解了函数的作用以及设置的总体过程  

整个过程。 但是、这对我不起作用。 它在专用于存储数据的数组中为我提供零。

我将添加代码功能的摘要、代码中存在一些冗余、我将保留这些冗余。

我正在使用 Keil、并已将  TARGET_IS_TM4C123_RB1、PART_TM4C123AH6PM 放入预处理器符号中。

  1. START 和 STOP 是冗余变量、用于测量中断发生的频率以及 SysTick 计数器及其处理程序。 如果我错了、请纠正我的问题。
  2. ADCseq0Handler 是在8级深度 FIFO 满时触发的。 然后、我们有 一个 uDMAChannelTransferSet、它应该负责接下来的64个样本。 然后 FIFO 将开始满、我们会再次运行。
  3. main()  设置时钟频率,启用计时器 ADC0、UDMA 和 Porte。 我们设置 SysTick 周期并将计时器周期(重复)设置为1/16000 s  
  4. init_adc()  将 ADC 的时钟设置为8MHz (必要步骤),禁用中断和序列发生器。  
  5. StepConfigure 将 ADC0的 SEQ 0配置为优先级为0、通道1作为输入、以引起中断、这是最后一步。 (现在 FIFO 中的所有其他步骤会发生什么情况?)
  6. 在特定的 uDMA 通道上、我们禁用不需要的属性(不知道它们是什么)、并启用突发传输。 控制参数是主结构体、数据大小、源地址不会递增、因为它们都来自同一个 FIFO、目的地址将递增、并且我们在64次这样的传输后进行仲裁
  7. 然后、我们设置阵列的地址并启用中断

我将得到数组中的所有0。 我已经检查了一个简单的 ADC 程序、即模拟输入配置是否正确。  

我希望有人能帮助我解决所有这些问题。 我觉得应该设置的所有内容都已经设置好了、但由于我没有这方面的经验、我找不到错误。   

欢迎提出任何建议。

Update1:我发现程序卡在 SysTickHandler 中,由于没有必要,我已将其删除,但它在 SS0 Handler 处停止。

Update2:在"ROM_TimerEnable (TIMER0_BASE、TIMER_A)"行之后、第一个元素加载正确的值、但所有其他元素都具有相同的值、大概是随机的。 此外、我在 SS0处理程序的开头放置了一个断点、但它从未达到?

update3:当然、中断有问题 。 基本 SysTick 处理程序不会执行、只是会停止。 感谢每个人的努力,我希望很快解决这个问题。  

最终更新:启动具有不同的矢量名称! 这就是导致所有这一切的原因。 感谢 Bob Crosby、希望您不要花太多时间来看看这个、 CB1_mobile、感谢 John Piliounis 和 Phil LaFayette10的建议、您的代码比我的代码好!  UDMA_ARB_1而不是 UDMA_ARB_1024

#include 
#include 

include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_adc.h"
#include "inc/hw_types.h"
#include "inc/hw_uma.h"
#include "driverlib/driver.h"
#driverlib/driver.h"

#include "driverlib/driver.h"#driverlib#driver.h"#include "driverlib.driver.h"#driverlib#driverlib#driverlib.driver.h"#include "driverlib#driverlib.driver.h"#include "driverlib.driver.h"#driverlib#driverlib.driverlib#driver.h"#include "driver.h"#driverlib#driverlib.driverlib.driverlib#driverlib.driver.h"#include "driver.h"#include "driverlib.driverlib#driverlib.driver.h"#include "driver.h"#driverlib#driverlib.










64

#pragma DATA_ALIGN (ucControlTable、1024)
uint8_t ucControlTable[1024];

静态 uint16_t ADC_OUT[ADC_SAMPLE_BUF_SIZE];
uint32_t n=0;

void init_adc (void);
静态 uint32_t g_ui32DMAErrCount = 0;
静态 uint32_t g_ui32SysTickCount;
易失性 uint32_t start、stop;


void uDMAErrorHandler (void)
{
uint32_t ui32Status;
ui32Status = ROM_uDMAErrorStatusGet ();
if (ui32状态)
{
ROM_uDMAErrorStatusClear ();
G_ui32DMAErrCount++;
}
}

void SysTickIntHandler (void)
{
//
//更新我们的系统节拍计数器。
//
G_ui32SysTickCount++;
}

void ADCseq0Handler()
{
停止= g_ui32SysTickCount;
ADCIntClear (ADC0_BASE、0);
N++;


if (!ROM_uDMAChannelIsEnabled (UDMA_CHANGE_ADC0))
{
uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT、UDMA_MODE_BASIC、(void *)(ADC0_BASE + ADC_O_SSFIFO0)、&ADC_OUT、ADC_SAMPLE_BUF_SIZE);


uDMAChannelEnable (UDMA_CHANGE_ADC0);
}

START = STOP;


}

int main (void)
{

SysCtlClockSet (SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHz);

SysCtlDelay (20);

ROM_SysCtlPeripheralEnable (SYSCTL_Periph_TIMER0);


SysCtlPeripheralEnable (SYSCTL_Periph_ADC0);//启用 ADC 模块的时钟
SysCtlDelay (10);//设置外设使能的时间

SysCtlPeripheralEnable (SYSCTL_Periph_UDMA);//启用 UDMA 的时钟
SysCtlDelay (10);


SysCtlPeripheralEnable (SYSCTL_Periph_GPIOE);//启用端口 E 的时钟
SysCtlDelay (30);

ROM_SysTickPeriodSet (SysCtlClockGet ()/1000000);//将 SysTic 计数器的周期设置为1us
ROM_SysTickIntEnable();
ROM_SysTickEnable();

ROM_TimerConfigure (TIMER0_BASE、TIMER_CFG_PERIODICASE);
ROM_TimerLoadSet (TIMER0_BASE、TIMER_A、ROM_SysCtlClockGet ()/16000 -1);//TODO:此处设置定时器装载值
ROM_TimerControlTrigger (TIMER0_BASE、TIMER_A、TRUE);


GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_2);

SysCtlDelay (80);

IntMasterEnable();

init_adc();


TimerEnable (TIMER0_BASE、TIMER_A);

start = g_ui32SysTickCount;



while (1)
{

}
}

void init_adc()
{

ADCClockConfigSet (ADC0_BASE、ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_Half、1);

SysCtlDelay (10);//设置时钟配置的时间

IntDisable (INT_ADC0SS0);
ADCIntDisable (ADC0_BASE、0);
ADCSequenceDisable (ADC0_BASE、0);
//禁用序列后,现在可以安全地加载新的配置参数

ADCSequenceConfigure (ADC0_BASE、0、ADC_TRIGGER_TIMER、0);

ADCSequenceStepConfigure (ADC0_BASE、0、0、ADC_CTL_CH1| ADC_CTL_END | ADC_CTL_IE);

ADCSequenceEnable (ADC0_BASE、0);//设置配置后、重新启用序列发生器
ADCIntClear (ADC0_BASE、0);

uDMAEnable();//启用 UDMA
uDMAControlBaseSet (ucControlTable);

ADCSequenceDMAEnable (ADC0_BASE、0);
//允许基于采样序列发生器(SS0)的 FIFO 级别生成 DMA 请求

uDMAChannelAttributeDisable (UDMA_CHANGE_ADC0、UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIOR| UDMA_ATTR_REQMASK);

uDMAChannelAttributeEnable (UDMA_CHANGE_ADC0、UDMA_ATTR_USEBURST);
//仅允许突发传输

uDMAChannelControlSet (UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT、UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_ARC_16 | UDMA_INC_1024);


uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT、UDMA_MODE_BASIC、(void *)(ADC0_BASE + ADC_O_SSFIFO0)、&ADC_OUT、ADC_SAMPLE_BUF_SIZE);


ADCIntEnable (ADC0_BASE、0);
IntEnable (INT_ADC0SS0);
uDMAChannelEnable (UDMA_CHANGE_ADC0);//启用 DMA 通道以便它可以执行传输

}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我正在处理您的代码。 我注意到您为起始示例提供的链接无效。 如果您检查该链接并再次发布、对我很有帮助。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    海报 Savo 的"额外努力"( 提供他的"总结")非常有用、因为它(清晰)描述了他的思维过程以及"逻辑流程"。   

    由于"实现最终目标"所需的"步骤顺序"、我的小组始终"要求此类总结"-因为它"使程序员(锁定到流程中)-同时强制执行 kiss -。

    相信海报的努力(实际上是他的方法)将会得到改进、如果他"更好地将其摘要与他们的特定代码块关联起来"、这将会"快速、轻松和增强"计划故障排除...

    分析此类代码-不引用此类代码、"顺序、独特元素"(海报或分析师自己的)似乎是一种"不完美的方法..."

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、

    我更新了链接。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您可能是对的、我在适当的软件开发方面没有真正的经验。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    什么"可能"是 "您的、"将复杂的"整体"减少为一系列"小的顺序步骤"-是一种经典的"问题解决方法"-通常被称为"kiss"。   (简化、结构、顺序、成功!)

    现在、虽然您在"摘要"中列出了这些步骤、但您没有在"不同的代码块"中列出这些步骤。     每一个此类代码块都应与其之前的描述性总结进行标识(因此相关)。    然后、只有这样、用户才能正确地"单独测试每个块"、这极大地"加快、简化和增强"项目/程序的成功

    您(仅限于)写下的"数组填充为零"(这很重要)、但您在测试中却"没有提及"、"每个代码块在其正确的进度(顺序)中"、以便集中精力确定代码"在哪里和何时"中断

    一个"快速/不干净"建议-使用"固定值"为 n ü µDMA 馈送数据-这样就消除了等式中的(任何/全部) ADC 误差。   然后"重新运行"、查看阵列是否按预期"填充"。

    通过将您的代码-然后将您的测试-拆分为最小的组成部分-您可以"加深您对每种代码的理解"-并显著提高您的成功几率

    攻击-作为一个不受纪律约束的"大失误"-(通常是一种匆忙/分散的努力)、这里也有太多人-会邀请许多"错误来源" 、使成功变得"不太可能"。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好 Savo。 我不太确定问题的原因、但我可以看到、从中断处理程序 ADCseq0Handler()例程内部、您检查是否初始化 if{}结构内的 UDMA 中断相关运算、而这些命令已经在 init_adc ()例程中发出一次。 请注意中断处理程序 ADCseq0Handler()例程中的 if{...}代码段并重新检查。
    John
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    嘿、John、
    感谢您的关注。 删除条件语句没有帮助。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您是否(尚未)尝试过"将已知值馈送到 µDMA 中"(不是来自 ADC 的值)、并注意这些"已知值"是否在缓冲器中安全到达?

    同样、将复杂的整个分解成非常小的(因此更易于理解的部分)并测试"每一个"、证明其优于随机的"代码执行"。

    缺乏清晰的书面计划几乎可以保证项目出现错误和延误! "通过代码工作"-减去此类计划-不是以"问题解决方法..."著称的

    注意:我的"小心眼"(此处有一些人指出)检测到您的语句、"将 ADC 时钟设置为8MHz (不需要)。"    事实上-这样的8MHz 设置上升(超过)您的(不需要)实际上是错误的!   ADC 必须接收"大于或等于16MHz"的系统时钟-才能满足其规格。   (这一点在 MCU 手册的 ADC 章节和手册后面的 ADC 规格中进行了说明。。。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Savo、请参阅以下内容、了解我的 ADC DMA 实现的一些代码段。 请注意、我使用 TM4C1294NCPDT、因此请注意。 此外、我不想通过提供复制粘贴 Cookie 截割代码来完全掌握您的手。 您必须在适当的区域中声明缺少的变量。 我已尝试对代码进行注释、以尽可能地提供帮助。 我不是最好的编程人员、但希望这能对您有所帮助。

    几个变量可让您快速开始:

    #define DMA_SAMPLING_FREQ 256000 //将其用于1000Hz 的虚拟16位采样
    
    //采样率,确定使 Timer0A 触发 ADC 采样
    的频率 uint32_t g_uiSamplingFreq = dma_sampling_FREQ; 

    主循环:

    //设置/配置中的某个位置...
    //初始化使用 DMA 对 ADC 进行采样所需的一切,由计时器
    init_adc_dma_SampleTimer()触发;
    
    // main ()中的某个位置...
    // DMA Sampling
    DMA_Sample_Start (NUM_DMA_SAples);
    
    //等待 DMA 数据就绪
    (g_ucDataReady = 0)
    {
    ;
    
    //如果我们有新的 DMA 数据,请在
    (g_ucDataReady)
    {时处理
    Process_yum_Data();
    } 

    下面是详细的函数...

    bool init_adc_dma_SampleTimer (void){
    ////////////////////////// 外设初始化////////////////////////////////////////////
    //这是一个很好的做法;切勿假定在调试会话之间完成了完整的系统复位。
    
    //禁用、复位和启用 uDMA,然后等待外设为访问做好准备。
    ROM_SysCtlPeripheralDisable (SYSCTL_Periph_UDMA);
    ROM_SysCtlPeripheralReset (SYSCTL_Periph_UDMA);
    ROM_SysCtlPeripheralEnable (SYSCTL_Periph_UDMA);
    while (!(ROM_SysCtlPeripheralReady (SYSCTL_Periph_UDMA)));
    
    //禁用、复位和启用 ADC0,然后等待外设为访问做好准备。
    ROM_SysCtlPeripheralDisable (SYSCTL_Periph_ADC0);
    ROM_SysCtlPeripheralReset (SYSCTL_Periph_ADC0);
    ROM_SysCtlPeripheralEnable (SYSCTL_Periph_ADC0);
    while (!(ROM_SysCtlPeripheralReady (SYSCTL_Periph_ADC0)));
    
    //禁用、复位和启用计时器0A,然后等待外设为访问做好准备。
    ROM_SysCtlPeripheralDisable (SYSCTL_Periph_TIMER0);
    ROM_SysCtlPeripheralReset (SYSCTL_Periph_TIMER0);
    ROM_SysCtlPeripheralEnable (SYSCTL_Periph_TIMER0);
    while (!(ROM_SysCtlPeripheralReady (SYSCTL_Periph_TIMER0)));
    
    //禁用、复位和启用 GPIO 端口 E,然后等待外设为访问做好准备。
    //我们要从引脚 PE_3对 ADC 进行采样
    ROM_SysCtlPeripheralDisable (SYSCTL_Periph_GPIOE);
    ROM_SysCtlPeripheralReset (SYSCTL_Periph_GPIOE);
    ROM_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOE);
    while (!(ROM_SysCtlPeripheralReady (SYSCTL_Periph_GPIOE)));
    
    //禁用、复位和启用 GPIO 端口 N,然后等待外设为访问做好准备。
    //我们希望在每次调用 ADC DMA ISR 处理程序时切换 Pn_0。
    ROM_SysCtlPeripheralDisable (SYSCTL_Periph_GPION);
    ROM_SysCtlPeripheralReset (SYSCTL_Periph_GPION);
    ROM_SysCtlPeripheralEnable (SYSCTL_Periph_GPION);
    while (!(ROM_SysCtlPeripheralReady (SYSCTL_Periph_GPION)));
    
    // Pn_0 LED 切换(如果要测试 LED 切换/采样率、请取消注释)
    //rom_GPIOPinTypeGPIOOutput (GPIO_PORTN_BASE、GPIO_PIN_0);
    ///ROM_GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_0、ui8Toggle);
    
    //////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////// uDMA Init //////////////////////////////////////////////////////////////////////////////
    
    //启用 UDMA 控制器以供使用。
    ROM_uDMAEnable();
    
    //设置 uDMA 控制表地址
    ROM_uDMAControlBaseSet (ucControlTable);
    
    //在中为 ADC 的 ADC0序列发生器3分配通道17
    ROM_uDMAChannelAssign (UDMA_CH17_ADC0_3);
    
    //将属性置于已知状态。 默认情况下应已禁用这些功能。
    ROM_uDMAChannelAttributeDisable (UDMA_CH17_ADC0_3、UDMA_ATTR_ALL);
    
    //设置 USEBURST 属性。 这比默认的允许单次或突发传输的总线使用更加高效。
    ROM_uDMAChannelAttributeEnable (UDMA_CH17_ADC0_3、UDMA_ATTR_USEBURST);
    
    //为 DMA 的主控制结构配置控制参数。
    // ADC FIFO (src)不递增,Ya buffoon! 仲裁数目:1.
    ROM_uDMAChannelControlSet (UDMA_CH17_ADC0_3 | UDMA_PRI_SELECT、
    UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_DST_INC_32 | UDMA_NEW_USEBURST |
    UDMA_ARB_1);
    
    ROM_uDMAChannelControlSet (UDMA_CH17_ADC0_3 | UDMA_ALT_SELECT、
    UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_DST_INC_32 | UDMA_NEW_USEBURST |
    UDMA_ARB_1);
    
    //设置主控制结构体的传输参数。
    //模式设置为乒乓,传输大小:1024
    uDMAChannelTransferSet (UDMA_CH17_ADC0_3 | UDMA_PRI_SELECT、
    UDMA_MODE_PINGONG、
    (void *)(ADC0_BASE + ADC_O_SSFIFO3)、
    G_ulADCValues_A、
    num_dma_transfers);
    
    ROM_uDMAChannelTransferSet (UDMA_CH17_ADC0_3 | UDMA_ALT_SELECT、
    UDMA_MODE_PINGONG、
    (void *)(ADC0_BASE + ADC_O_SSFIFO3)、
    G_ulADCValues_B、
    num_dma_transfers);
    
    //此函数启用特定的 uDMA 通道以供使用。 必须先使用此函数启用通道、然后才能使用该通道来执行 UDMA 传输。
    //当 uDMA 传输完成时,UDMA 控制器会自动禁用该通道。 因此、应在之前调用此函数
    //启动任何新的传输。
    ROM_uDMAChannelEnable (UDMA_CH17_ADC0_3);
    
    //////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////// ADC0SS3初始化//////////////////////////////////////////
    
    //为引脚 PE_3配置模拟 ADC 功能。
    ROM_GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_3);
    
    //将 ADC 配置为在480MHz 时使用 PLL 除以15以获得32MHz 的最大 ADC 时钟。 这给出了1MSPS 的最大采样率?
    ADCClockConfigSet (ADC0_BASE、ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL、15);
    
    //设置外部 ADC 基准(VREFA+)。 如果您没有外部基准、请注意设置为内部基准!
    ROM_ADCReferenceSet (ADC0_BASE、ADC_REF_EXT_3V);
    
    //在配置序列之前禁用该序列的良好做法
    ROM_ADCSequenceDisable (ADC0_BASE、DMA_ADC_SEQUENCER]);
    
    //将 ADC 配置为从计时器触发
    ROM_ADCSequenceConfigure (ADC0_BASE、DMA_ADC_SEQUENCER, ADC_TRIGGER_TIMER,0 /*Priority*/);
    
    //配置序列上的步骤。 在单端模式下对通道进行采样(默认)、并在最后一次转换后配置中断标志
    ROM_ADCSequenceStepConfigure (ADC0_BASE、DMA_ADC_SEQUENCER、0、ADC_CTL_CH0/* PE3*/| ADC_CTL_IE | ADC_CTL_END);
    
    //在中断控制器(NVIC)上启用 ADC 序列0中断。
    ROM_IntEnable (INT_ADC0SS3);
    
    //此函数启用指示的 ADC 中断源。 只有启用的源才能反映到处理器中断;
    //禁用的源对处理器没有影响。
    ROM_ADCIntEnableEx (ADC0_BASE、ADC_INT_DMA_SS3);
    
    //由于 ADC0采样序列3现在已配置,因此必须将其启用。
    ROM_ADCSequenceEnable (ADC0_BASE、DMA_ADC_SEQUENCER]);
    
    //////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////// Timer0A 初始值//////////////////////////////////////////////////
    
    //将 Timer0配置为周期
    ROM_TimerConfigure (TIMER0_BASE、TIMER_CFG_PERIODICASE);
    
    //加载 Timer0_A、具有采样频率 中断速度。
    //我们执行(SamplingFreq.- 1),因为计时器在0上触发。
    ROM_TimerLoadSet (TIMER0_BASE、TIMER_A、g_ui32SysClock /(g_uiSamplingFreq - 1));
    
    //启用定时器0在满足其装载值时触发 ADC0SS3
    TimerControlTrigger (TIMER0_BASE、TIMER_A、TRUE);
    
    //启用可能导致 ADC 触发事件的计时器事件。
    TimerADCEventSet (TIMER0_BASE、TIMER_ADC_TIMEOUT_A);
    
    返回1;
    } 
    bool dma_Sample_Start (uint16_t samples)
    {
    如果(_SAMPLING)
    返回 true;
    
    //初始化样本停止序列标志
    G_ui8ADC_DMA_Sample_Stop = 0;
    
    //重置 g_ucDataReady 标志,以便下一个 Main()循环不会重复使用旧的 ADC 数据
    G_ucDataReady = 0;
    
    采样= true;
    
    //设置样本
    _samples =样片;
    
    //取消挂起来自中断控制器的 ADC0SS3中断,以防万一。
    ROM_IntPendClear (INT_ADC0SS3);
    
    //加载 Timer0_A、具有采样频率 中断速度
    ROM_TimerLoadSet (TIMER0_BASE、TIMER_A、g_ui32SysClock /(g_uiSamplingFreq - 1));
    
    //启用定时器0在满足其装载值时触发 ADC0SS3。
    TimerControlTrigger (TIMER0_BASE、TIMER_A、TRUE);
    
    //启用可能导致 ADC 触发事件的计时器事件。
    TimerADCEventSet (TIMER0_BASE、TIMER_ADC_TIMEOUT_A);
    
    ROM_uDMAChannelDisable (UDMA_CH17_ADC0_3);
    
    
    ROM_uDMAChannelTransferSet (UDMA_CH17_ADC0_3 | UDMA_PRI_SELECT、
    UDMA_MODE_PINGONG、
    (void *)(ADC0_BASE + ADC_O_SSFIFO3)、
    G_ulADCValues_A、
    num_dma_transfers);
    ROM_uDMAChannelTransferSet (UDMA_CH17_ADC0_3 | UDMA_ALT_SELECT、
    UDMA_MODE_PINGONG、
    (void *)(ADC0_BASE + ADC_O_SSFIFO3)、
    G_ulADCValues_B、
    num_dma_transfers);
    
    //为中的 ADC 启用 ADC0序列3通道。
    ROM_uDMAChannelEnable (UDMA_CH17_ADC0_3);
    
    //在中断控制器(NVIC)上启用 ADC 序列0中断。
    ROM_IntEnable (INT_ADC0SS3);
    
    //此函数启用指示的 ADC 中断源。
    //只有启用的源才可以反映到处理器中断;
    //禁用的源对处理器没有影响。
    ROM_ADCIntEnableEx (ADC0_BASE、ADC_INT_DMA_SS3);
    
    //启用基于 ADC0采样序列发生器3的 FIFO 深度生成的 DMA 请求。
    ADCSequenceDMAEnable (ADC0_BASE、DMA_ADC_SEQUENCER]);
    
    //启用 ADC 序列发生器在计时器触发时进行采样
    ROM_ADCSequenceEnable (ADC0_BASE、DMA_ADC_SEQUENCER]);
    
    //启用 Timer0_A 对 ADC 进行采样!!! 这应该会启动 ADC 采样
    ROM_TimerEnable (TIMER0_BASE、TIMER_A);
    
    返回 true;
    } 
    void ADC3IntHandler (void){
    
    静态易失性 uint16_t ui16inc = 0;//积分/抽取计数器、当 ui16inc = 255时、我们发布新结果
    静态易失性长累加器 A=0L;// Heres、我们在其中集成 ADC 样本
    静态易失性 long accumulatorB=0L;// Heres、其中我们集成了 ADC 样本
    
    //'Ping'和'Pong'缓冲器的累加器变量,
    //最终复制到 g_f32DecimatedArray[]
    volatile uint32_t resulta = 0;
    volatile uint32_t resultB = 0;
    
    ROM_ADCIntClear (ADC0_BASE、DMA_ADC_SEQUENCER]);
    
    ADCIntClearEx (ADC0_BASE、ADC_INT_DMA_SS3);
    
    volatile uint32_t ui32Mode;
    
    //切换 Pn_0 LED、用于通过示波器或频率计数器验证采样率
    //ui8Toggle =!ui8Toggle;
    ///ROM_GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_0、ui8Toggle);
    
    //抓取模式
    ui32Mode = ROM_uDMAChannelModeGet (UDMA_CH17_ADC0_3 | UDMA_PRI_SELECT);
    
    // Ping 缓冲区中有数据
    if (ui32Mode = uDMA_MODE_STOP)
    {
    // Ping 缓冲区中有256个样本,因此累加
    对于(uint16_t i=0;i<256;i++){
    accumulatorA += g_ulADCValues_a[i];
    }
    
    //抽取
    resulta = accumulatorA >> 4;//右移四个虚拟位来执行除法运算
    
    //保存结果,递增 g_f32DecimatedArray 索引
    G_f32DecimatedArray[ui16inc++]= resulta;
    
    //转储累加器
    accumulatorA = 0L;
    
    //为'Ping' Buffer 设置新的传输
    ROM_uDMAChannelTransferSet (UDMA_CH17_ADC0_3 | UDMA_PRI_SELECT、UDMA_MODE_PINGONG、
    (void *)(ADC0_BASE + ADC_O_SSFIFO3)、
    G_ulADCValues_A、
    num_dma_transfers);
    //启用 UDMA 通道
    ROM_uDMAChannelEnable (UDMA_CH17_ADC0_3);
    }
    
    ui32Mode = ROM_uDMAChannelModeGet (UDMA_CH17_ADC0_3 | UDMA_ALT_SELECT);
    
    // Pong 缓冲区中有数据
    if (ui32Mode = uDMA_MODE_STOP)
    {
    // Pong 缓冲区中有256个样本,因此累加
    对于(uint16_t i=0;i<256;i++){
    accumulatorB += g_ulADCValues_B[i];
    }
    
    //抽取
    resultb = accumulatorB >> 4;//右移四个虚拟位来执行除法运算
    
    //保存结果,使 g_f32DecimatedArray[]索引递增
    G_f32DecimatedArray[ui16inc++]=结果 B;
    
    //转储累加器
    accumulatorB = 0L;
    
    //为'Pong'缓冲器设置新的传输
    ROM_uDMAChannelTransferSet (UDMA_CH17_ADC0_3 | UDMA_ALT_SELECT、UDMA_MODE_PINGONG、
    (void *)(ADC0_BASE + ADC_O_SSFIFO3)、
    G_ulADCValues_B、
    num_dma_transfers);
    //启用 UDMA 通道
    ROM_uDMAChannelEnable (UDMA_CH17_ADC0_3);
    }
    
    //如果我们将 g_f32DecimatedArray[]递增了样本数,请停止此处理程序,以便我们可以处理数据
    if (ui16inc =_samples)
    {
    ROM_TimerDisable (TIMER0_BASE、TIMER_A);
    
    ROM_TimerIntClear (TIMER0_BASE、TIMER_TINA_TIMEOUT);
    
    ROM_IntPendClear (INT_ADC0SS3);
    
    //禁止基于 ADC0采样序列发生器3的 FIFO 深度生成 DMA 请求。
    ROM_ADCSequenceDMADisable (ADC0_BASE、DMA_ADC_SEQUENCER]);
    
    //获取中断状态,以便我们可以清除它。 否则、我们将返回到该中断处理程序中
    uint32_t ui32ADCIntStatusEx = ROM_ADCIntStatusEx (ADC0_BASE、false);//未屏蔽
    ADCIntClearEx (ADC0_BASE、ui32ADCIntStatusEx);
    
    //重置 DMA 增量计数
    ui16inc = 0;
    
    采样= 0;
    
    //表示我们有要处理的新数据
    G_ucDataReady = 1;
    }
    
    } 

    请注意、此示例包括 ADC 样本的集成和抽取、基本上可以实现更精细的 ADC 分辨率(基本上、采样率大于所需的速率、从而为采样数据创建虚拟分辨率)

    您可以随意提问、但这至少应该让您走下去。 谢谢!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    此帖子还附加了一个 TM4C123示例:
    e2e.ti.com/.../2381981