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.

[参考译文] CCS/EK-TM4C123GXL:高频 ADC 采样

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/662525/ccs-ek-tm4c123gxl-high-frequency-adc-sampling

器件型号:EK-TM4C123GXL
主题中讨论的其他器件: TM4C123

工具/软件:Code Composer Studio

豪迪!

我正在尝试配置 Tiva TM4C23G 微控制器以1MHz 的频率收集电压样本。  我需要使用 ADC 对任意时间发生的脉冲进行采样、并将数据存储到后续存储中

分析。  但是、需要在后台由硬件尽可能处理采样、以便为其他任务释放 CPU。

此外、最好在脉冲发生之前有一种方法来获得多个数据点。

我目前认为、这可以通过使用计时器中断触发 ADC 采样并配置 UDMA 来收集样本来实现。  ADC 中断可以检测到该脉冲、

这将调用函数进行数据分析、或通过 UART 传输数据以在其他位置进行处理。  但我不确定如何配置 ADC 以如此高的速率进行采样、因此我完全不熟悉

UDMA。  有人能给我讲些什么吗?  简单的示例代码也会非常有用。

提前感谢您!

Derek Janak59.

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

    要达到该采样率、您几乎肯定需要使用 uDMA 来处理 ADC 方面的问题。 但是、从头开始完全设置将会非常复杂。

    如果您不熟悉这两个模块、我建议将问题分为两个阶段。

    第1阶段是使 ADC 高速工作、不确定是否需要1MSPS、但至少要超过500kSPS、因此您对 ADC 方面有信心。 实际上、您的帖子让我想起了最近针对同一 MCU 在此处解决的另一个查询、并且在此过程中发布了许多示例代码。 我认为这篇文章在学习过程 中对您非常有帮助:e2e.ti.com/.../631388

    请注意、我们还在 TivaWare 示例中的[安装路径]\TivaWare_C_Series-2.1.4.178\examples\peripherals\adc 下提供了 ADC 的示例代码。

    现在、第2阶段是将 UDMA 集成到固件中以消除该开销。 这也会使您获得良好的速度改进。 UDMA 部分将会更加复杂、我们没有 ADC+UDMA 的示例代码、但有很多 E2E 帖子深入探讨了该主题、许多用户发布了他们代码的片段。 实际上、我上面提到的帖子是社区成员 Josue Pareja 的评论、他向 ADC+UDMA 配套资料发布了几个链接。

    如果您真的想在深入了解 ADC 之前了解 UDMA、我们还提供了用于此的 TivaWare 示例、例如[安装路径]\TivaWare_C_Series-2.1.4.178\examples\boards\ek-tm4c123gxl\UDMA_demo -该示例不包含任何 ADC 代码、但对于初始学习而言很有用。

    此外、我们的文档将在整个过程中成为您的朋友。 器件数据表和 TivaWare 文档(如 Driverlib 用户指南(SW-TM4C-DRL-UL-UF-2.1.4.178.pdf)有时会很密集、但它们都将提供大量相关详细信息。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Howdy Ralph、

    感谢您的回答。  很抱歉、我的回复很晚;我更改了电子邮件、但在访问 E2E 帐户时遇到问题。

    我一直在解决这个问题、我似乎让 uDMA 工作。  我似乎还实现了所需的1MSPS 采样率。  该代码适用于连续采样情况、但我现在正在尝试使用外部 GPIO 触发器触发1024个采样。  但是、我的 ADC 中断无法清除时、似乎存在问题。

    我正在通过由引脚 B4生成的外部中断触发 ADC。  我删除了代码中与 UDMA 和采样相关的所有部分、我只关注 ADC 中断。  在引脚第一次触发中断后、该函数似乎会卡在中断中、并且中断标志将不会清除(ADCIntStatus 返回1)。  下面是相关代码:

    void ADC0IntHandler()
    {
    uint32_t status;
    STATUS = ADCIntStatus (ADC0_BASE、0、TRUE);
    ADCIntClear (ADC0_BASE、0);
    
    //我尝试这样做是为了确保有足够的周期来清除中断标志。
    SysCtlDelay (16000000u / 3U);
    }
    
    void ConfigureADC (void)
    {
    ADCSequenceConfigure (ADC0_BASE、0、ADC_TRIGGER_EXTERNAL、0);
    GPIOADCTriggerEnable (GPIO_PORTB_BASE、GPIO_PIN_4);
    
    ADCSequenceStepConfigure (ADC0_BASE、0、0、ADC_CTL_CH0);
    ADCSequenceStepConfigure (ADC0_BASE、0、1、ADC_CTL_CH1);
    ADCSequenceStepConfigure (ADC0_BASE、0、2、ADC_CTL_CH2);
    ADCSequenceStepConfigure (ADC0_BASE、0、9、ADC_CTL_CH3);
    ADCSequenceStepConfigure (ADC0_BASE、0、4、ADC_CTL_CH4);
    ADCSequenceStepConfigure (ADC0_BASE、0、5、ADC_CTL_CH5);
    ADCSequenceStepConfigure (ADC0_BASE、0、6、ADC_CTL_CH6);
    ADCSequenceStepConfigure (ADC0_BASE、0、7、ADC_CTL_CH7 |ADC_CTL_IE | ADC_CTL_END);
    
    ADCSequenceEnable (ADC0_BASE、0);
    ADCIntClear (ADC0_BASE、0);
    }
    
    void ConfigureInterrupts (void)
    {
    IntMasterEnable();
    
    GPIOPadConfigSet (GPIO_PORTB_BASE、GPIO_PIN_4、GPIO_Strength _2mA、GPIO_PIN_TYPE_STD_WPD);
    GPIOIntTypeSet (GPIO_PORTB_BASE、GPIO_PIN_4、GPIO_FALLING_EDGE);
    
    ADCIntEnable (ADC0_BASE、0);
    ADCIntRegister (ADC0_BASE、0、ADC0IntHandler);
    
    }
    
    int main (void)
    {
    //将时钟设置为直接从晶体运行。
    SysCtlClockSet (SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
    SYSCTL_XTAL_16MHz);
    
    //初始化并设置端口
    PortFunctionInit();
    
    ConfigureADC();
    ConfigureInterrupts();
    
    //在计时器运行时永久循环。
    while (1)
    {
    状态= ADCIntStatus (ADC0_BASE、0、TRUE);
    }
    } 

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

    尊敬的 Derek:

    我缺少一些仍然像 PortFunctionInit 函数和用于 GPIO 触发器的 ISR 这样的信息、如果我也看不到这些信息、我很难获得完整的图片。

    例如、似乎所有 SysCtlPeripheralEnable 都不存在、但我无法判断它们是否位于 PortFunctionInit 函数中。

    此外、不确定这是否有帮助、但 E2E 上的其他人发布了 GPIO 触发 ADC 的代码: https://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/p/430355/1543938#1543938

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    "以收集频率为1MHz 的电压样本。 "

    在开始之前先阅读勘误表、以确保芯片能够做到这一点。

    然后将芯片放入其空间、查看其性能是否适合您的应用。

    DMA 是实现这种速度的唯一方法。

    "有人能给我讲些什么吗? "

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

    [引用 user="Derek Janak59">我将通过引脚 B4生成的外部中断触发 ADC。   在引脚第一次触发中断后、该函数似乎卡在中断中并且中断标志将不会清除(ADCIntStatus 返回1)。[/quot]

    这是一个"纯粹的"割道-但可能证明是一个"合理的"割道。   (有一个希望)

    未提供任何证据表明您 的"PB4 GPIO 中断"已创建 、然后被处理-并被清除!    实际上、您已经很好地处理 了"ADC0的中断处理程序"、 对于 PB4的 GPIO 来说、这不是!    虽然"未知"(至少不清楚)、但如果此类 PB4中断被证明是有用的(或必需的)-您在 ADC0中断中的"进入"、 然后"离开失败"-(可能)表示 (某些)中断之间的链接... (我注意到,没有其他"合理"的理论得到发展!)

    为了进一步 "促进我的理论"- TM4C123手册中介绍了这个"摘要":  (注意: 下面是真实副本:)

    10.2.2.1 ADC 触发源
    '任何 GPIO 管脚都可以通过 GPIO ADC 控制 (GPIOADCCTL)寄存器配置为 ADC 的外部触发。   如果 GPIO 被配置为非屏蔽中断管脚( GPIOIM 中相应的位被置位)、 并且该端口产生中断、 那么触发信号就会发送到 ADC。

    如果 ADC 事件多路复用器选择(ADCEMUX)寄存  器配置为使用外部触发器、则启动 ADC 转换。    见833页。"

    实际上、您已经利用了"PB4 的"ADC 触发能力" (以及良好的触发能力)、但 "可能 无法解释"  没有   "PB4的处理程序及其服务!"    (也许...)    (注意:割道边南悬挂-吹硬启动板...)

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

    我没有为 GPIO 触发器定义 ISR,PortFunctionInit()函数由 TI pinmux 实用程序自动生成。 我目前没有访问 PortFunctionInit 代码的权限、但我将在下一次机会发布它。 除此之外、显示的代码表示我的完整代码、减去 UDMA。

    正如 Danny F 所建议的、我验证了芯片能够以1MHz 的频率进行采样、并且在连续采样和触发定时器时能够在代码中验证这一点。 但是、从外部引脚触发已将扳手投入使用。

    正如 CB1_MOBILE 所建议的那样、我确实认为退出 ISR 失败可能是由于一个已断言的 GPIO 中断、所以我尝试在之前版本的代码中清除端口 B4上的 GPIO 中断标志。 这无法解决我的问题。 我认为我使用的功能如下:

    uint32_t status = GPIOIntStatus (GPIO_PORTB_BASE、TRUE);
    GPIOIntClear (GPIO_PORTB_BASE,STATUS);

    通过观察表达式监视状态、即使在 ADC 中断被触发时、它也保持为零。 此外、对 GPIOIntClear 的调用不会影响我的问题。

    我还尝试使用0xFFFF 来调用 GPIOIntClear 和 ADCIntClear 函数作为 STATUS 参数、希望这样可以清除所有相关的中断、但这也不成功。

    我已经确保引脚 B4上的事件只发生一次以第一次触发中断、所以我怀疑它将中断重新置为有效。 为了测试这一点、我甚至尝试在触发后将其接地、以验证浮点引脚是否不会持续触发中断。

    我和同事都被骗了。 请提供建议。

    谢谢、

    Derek
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    "但是、从外部引脚触发已将扳手扔进了一些东西中。"

    在这种情况下、您可能需要单步执行 ISR、并计算执行 ISR 所需的周期数以及 ISR 开销、以查看 ISR 执行速度是否足够快。

    要在80MHz MCU 上采样1Msps、必须在80个周期内运行 ISR。 约20个时钟周期的开销、这意味着您还有60个时钟周期。 当您从 ISR 内部使用库函数时、这可能还不够。

    我会尝试您的当前方法在较低速度下工作、看看它是否起作用;如果它在较低速度下工作、而不是在较高速度下工作、您就知道问题所在。 然后、尽量加快 ISR 的速度、并滚动自己的代码、而不是依赖库。

    此外、还应考虑 DMA。 借助 ISR、MCU 的处理能力非常小、只剩下任何其他任务。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    感谢您响应创建"ADC 触发"端口 B4中断的建议、然后正确处理该中断。

    我对丹尼的建议投赞成票、他建议"降低 ADC 转换率"。 (我至少将其减半、用于启动器。) 有了"手头的事实"-您的设计不确定、"只是什么、在哪里、何时"。 大幅降低转换速率(暂时)可能会使设计取得成功-这最能让您"有选择地探查弱点"。

    我看到 PB4和/或"相关"被设置为"边沿触发器"。 您(最近和实际)是否监测过"PB4的信号"、以确保"一个和只有一个边沿脉冲"(每个所需的转换)到达? 这也证明了观察 PB4的"波形"(良好、干净、快速上升/下降)以及 PB4的脉冲宽度很有用。 (Fi/I 已注意到"缓慢转换"信号作为"边沿触发器"出现故障(有时)。)

    还请注意、"PB4"有(部分)不恰当-也许您(临时替代)的另一个 GPIO -可能会"突出" PB4 (可能)引入的任何潜在"限制"。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    由于这是一个由 TI 运营的论坛、我必须谨慎对待我所说的内容-我曾因 TI 员工表示不同意而受到警告。

    因此,我建议你回到我先前建议的内容:这些词是仔细选择的。 阅读线路之间的内容、倾听未说的内容。

    如果您幸运、一些 TI 员工可能会为您提供以1Msps 运行 ADC 的简短代码、以便您进行实验。

    祝你好运。

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

    海报 Danny (未解决)-最近的帖子-关注问题。

    "降低 MCU 运行速度"的建议-"简化任务成功"-绝不会贬损(任何)供应商!    相反、这是一种长期、高度成功且众所周知的"诊断技术"、我知道这是一种"标准操作程序"、在全球的大公司和小公司都是如此。

    丹尼(最近一次)的写作背景不清楚。   我撰写这篇文章是为了确保"高度正确和适当"的诊断方法(减慢 MCU 执行速度) 不会被(不公平)拒绝...

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

    尊敬的 Derek:

    进一步查看您的代码、我想知道此调用是否需要从 ConfigureADC 函数转移到 ConfigureInterrupts 函数。  ConfigureInterrupts 函数用于设置 GPIO 引脚类型、我想知道这是否会导致冲突。 现在、我在您的实现中看到的主要区别是、示例代码(假定)的作用是函数调用的顺序。

    GPIOADCTriggerEnable (GPIO_PORTB_BASE、GPIO_PIN_4); 

    不过、我同意 Danny 和 CB1的看法、即立即将其设置为1MHz 采样并不是最佳方法。 我建议使用较低的速率、让我们确保您可以正确地整体触发 ADC、然后您可以提高速度。

    我将尝试运行您的代码和我在明天之前引用的示例的精简版本、以查看其他可能发生的情况。

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

    Howdy All、

    我之前曾尝试通过包括延迟、while 循环以及其他代码来减慢 ISR 的执行速度。  问题不在于 ISR 的执行速度。  此外、这个问题与使 ISR 运行得更快无关;它是为了尝试清除中断标志。

    重申一下:以1MSPS 的速率运行 ADC 不再是一个问题; 它正在清除外部引脚中断、这会导致困难。  此外、我已经能够验证 PB4只能看到一个边沿。  请通读我之前的帖子、了解我已经尝试了哪些解决方案;我收到的许多建议与上面列出的我自己的调试尝试没有什么不同。

    下面是先前请求的 PortFunctionInit()代码:

    void PortFunctionInit(void){
    
    //
    //启用外设时钟
    //
    SysCtlPeripheralEnable (SYSCTL_Periph_ADC0);
    SysCtlPeripheralEnable (SYSCTL_Periph_ADC1);
    SysCtlPeripheralEnable (SYSCTL_Periph_UART0);
    SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
    SysCtlPeripheralEnable (SYSCTL_Periph_GPIOB);
    SysCtlPeripheralEnable (SYSCTL_Periph_GPIOC);
    SysCtlPeripheralEnable (SYSCTL_Periph_GPIOD);
    SysCtlPeripheralEnable (SYSCTL_Periph_GPIOE);
    SysCtlPeripheralEnable (SYSCTL_Periph_GPIOF);
    
    //
    // ADC AIN2的使能引脚 PE1
    //
    GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_1);
    
    //
    // ADC AIN3的使能引脚 PE0
    //
    GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_0);
    
    //
    // ADC AIN4的使能引脚 PD3
    //
    GPIOPinTypeADC (GPIO_PORTD_BASE、GPIO_PIN_3);
    
    //
    // ADC AIN8的使能引脚 PE5
    //
    GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_5);
    
    //
    // ADC AIN10的使能引脚 PB4
    //
    GPIOPinTypeADC (GPIO_PORTB_BASE、GPIO_PIN_4);
    
    //
    // ADC AIN6的使能引脚 PD1
    //
    GPIOPinTypeADC (GPIO_PORTD_BASE、GPIO_PIN_1);
    
    //
    // ADC AIN1的使能引脚 PE2
    //
    GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_2);
    
    //
    // ADC AIN11的使能引脚 PB5
    //
    GPIOPinTypeADC (GPIO_PORTB_BASE、GPIO_PIN_5);
    
    //
    // ADC AIN7的使能引脚 PD0
    //
    GPIOPinTypeADC (GPIO_PORTD_BASE、GPIO_PIN_0);
    
    //
    // ADC AIN5的使能引脚 PD2
    //
    GPIOPinTypeADC (GPIO_PORTD_BASE、GPIO_PIN_2);
    
    //
    // ADC AIN0的使能引脚 PE3
    //
    GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_3);
    
    //
    // ADC AIN9的使能引脚 PE4
    //
    GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_4);
    
    //
    //为 GPIOInput 启用引脚 PC5
    //
    GPIOPinTypeGPIOInput (GPIO_PORTC_BASE、GPIO_PIN_5);
    
    //
    // GPIOOutput 的使能引脚 PF1
    //
    GPIOPinTypeGPIOOutput (GPIO_PORTF_BASE、GPIO_PIN_1);
    
    //
    // GPIOOutput 的使能引脚 PF3
    //
    GPIOPinTypeGPIOOutput (GPIO_PORTF_BASE、GPIO_PIN_3);
    
    //
    //为 GPIOOutput 启用引脚 PF2
    //
    GPIOPinTypeGPIOOutput (GPIO_PORTF_BASE、GPIO_PIN_2);
    
    //
    // UART0 U0RX 的使能引脚 PA0
    //
    GPIOPinConfigure (GPIO_PA0_U0RX);
    GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0);
    
    //
    // UART0 U0TX 的使能引脚 PA1
    //
    GPIOPinConfigure (GPIO_PA1_U0TX);
    GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_1);
    } 

    感谢大家的帮助!

    此致、

    Derek

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

    [引用 user="Derek Janak59"]请通读我之前的帖子,了解我已经尝试了哪些解决方案;我收到的许多建议与我自己的建议没有什么不同

    您是否可以考虑以下事项:

    • 您通过上面的建议是(许多)"梳理"多个帖子以代表 您尝试"首先查找-然后查找详细信息" 。
    •   如果 您要收集(所有这些过去的建议)在 您的最新帖子中突出显示它们、那么它是否会更有效-并表现得更好、"帮助者关怀/关注"?

    我不相信这里的人会要求您降低 仅 ISR 的执行速度"-相反降低整个 MCU 的代码执行速度 (通过系统时钟设置) 影响(大部分)一切的因素、以及(几个)在这里的经验、相信 (可能)会证明是有启发性的。   (当前 (其他)"尝试" 尚未成功-因此此请求...)

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

    尊敬的 Derek:

    感谢您的分享、我能够运行您的代码、我想我已经解决了这个问题。

    对于中断启用、您似乎需要另一个看起来不存在的 API 调用:

    IntEnable (INT_ADC0SS0); 

    我在中添加了该值后、看起来 INT 会成功清除。

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

    感谢您为帮助我所做的所有努力。 我仍然很难使该代码正常工作、我决定暂时尝试不同的解决方案。 我可以稍后再讨论这个问题,但我目前需要重新关注守则的其他方面。 我非常感谢你代表我所作的一切努力。

    此致、

    Derek