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/TM4C123GH6PM:具有 UDMA 的 Tiva 定时器触发 ADC

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/651146/ccs-tm4c123gh6pm-tiva-timer-triggered-adc-with-udma

器件型号:TM4C123GH6PM

工具/软件:Code Composer Studio

大家好、

我希望使用 Tiva TM4C123GH6PM 在计时器触发的 ADC 上设置 UDMA。 到目前为止,我发现这个主题非常有启发性:   。

不过、这里的示例代码工作正常、我想获得一个使用 ADC_TRIGGER_TIMER 而不是 ADC_TRIGGER_Always 的解决方案。 原因是我希望有一个精确的采样间隔、以便能够使用我已经设置的 CMSIS DSP 库执行信号处理。 我获取了原始代码并修改了 ConfigADC0函数、如下所示:

遗憾的是、ADC 触发似乎永远不会发生、返回的值始终为9999 (即在主循环之前初始化的值)。

是否有人看到我出错的地方?

是否有人成功创建了一个持续使用定时器触发的 ADC 执行 DMA 传输的 Tiva 项目?

谢谢、

Jim

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    尊敬的 James:
    请看以下文章中的示例:
    e2e.ti.com/.../643173
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    感谢 Bob。 这是一个极好的示例。

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

    Bob、

    该代码太棒了。 我能够对其进行修改并启动并运行一个非常酷的实时 DSP 示例。

    我要在这里展开的一件事是为 DMA 设置多个通道。 我不清楚如何使用您的代码来执行该操作。 给我一个指针吗?

    祝您愉快的假期、

    Jim

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    如果目标是大致同时对两个或多个通道进行采样、只需设置 ADC 序列来转换更多通道即可。 在第一个 ADC 中断之后、第一个缓冲器将用通道中的交替采样填充。 您可以在处理数据时拆分样本、或设置两个存储器到存储器软件触发的 UDMA 通道、以将每个其他条目复制到单独的缓冲区中。 此方法可扩展到多个通道。

    如果需要在几乎没有时间差的情况下采集样本、您可以使用由同一定时器触发的 ADC 模块1对第二个通道进行采样。 您需要设置第二个 uDMAChannel 来从 ADC 模块1传输样本。 该方法仅限于两个同步通道。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢

     

    我正在尝试实现您提到的第一种解决方案、这种解决方案应导致在 ADC_OUT 缓冲器中出现交替采样。 我尝试更改 ADC_init 函数中的几行:  

      GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_2);  

      输入

      GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_3 | GPIO_PIN_2);

     

      和  

       

       ADCSequenceStepConfigure (ADC0_BASE、0U、0U、ADC_CTL_CH0| ADC_CTL_END | ADC_CTL_IE);

       输入

      ADCSequenceStepConfigure (ADC0_BASE、0U、0U、ADC_CTL_CH0);

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

     

    再一次、目标是 ADC_OUT 缓冲器中的样本在 PE3和 PE2捕获的值之间交替。 但是、似乎只有两个通道的其中一个值进入缓冲器。 我错过了什么还是犯了个错误?

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

    您的代码显示正确-但是对于“ ADCSequenceEnable()”的外观 ,它应该(跟在)您的最后一个, “ADCSequenceStepConfigure()”。

    由于该函数显示(未显示)-它可能会在代码中的早期出现-因此这可能是可疑的。

    您已经很好地添加 了"GPIOPinType ()" (针对您添加的 ADC 通道)-只要您使用"序列3以外的采样序列(其他)"-您转换第二个通道的能力应该是不受阻碍的...

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    ,我找到了根本原因,就是我的仲裁数目需要是2而不是1。 结合上述步骤、我有一个可以使用的解决方案。

    再次感谢、
    谢谢
    Jim
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    CMSIS 库是否可与 TivaWare 配合使用(您的示例)? 我尝试过类似的操作、但它只是 CMSIS 函数上的硬库。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Savo、

    您是否能够运行 CMSIS 库中包含的示例代码? 查看此主题 中的 Bruno Saraiva 帖子:  

    我完全按照他的说明操作、并启动并运行示例代码。 我构建特定应用的方式是:

    1.对我的用例进行轻微调整(需要一个 BPF)

    2.从我在这个网站上获得的工具生成的系数 ()转换为.txt

    3.使用 python 脚本解析该.txt 并将其转换为外部头文件 Coeffs.h

    4.对上述 Coeffs.h 进行外部引用

    5、拉入发布的代码 Bob 来设置 UDMA 并将其合并、使其以与 CMSIS 示例代码类似的方式运行。

    6.将 Bob 的代码中的一些函数折叠到外部.h 文件中,以减少混乱并使其可移植到多个应用程序

    就结构而言、我所做的就是"ping-ponging"、在两个通道的每个通道上运行相同的 BPF 滤波器(转换为浮点后)、然后运行 RMS 并检查阈值  

    我在尝试运行 FIRS 时注意到的一些"明白了":

     您必须确保自己

    a)为要使用的每个滤波器设置 ARM_fir 实例结构

    b)使用所需系数通过 arm_fir 初始化上述结构

    c)确保所有指针都正确

    d)确保您的输入和输出缓冲器大小相同且正确

    e)对足够大的 UDMA 缓冲器进行采样、这样您就可以在不丢失样本的情况下及时完成所需的 FIR (否则您将会得到混叠)。 我的滤波器是128个抽头、在48kHz 的采样率下足够好、但如果采样速度快于该速率、您可能希望开始减少抽头数

    f)请记住、每次运行滤波器时、输出中都会出现零输入响应。 这就是为什么我使用"offset"变量来排除该响应并仅保留我信任的样本、这些样本更能指示我要测量的过程变量

    总之、这是我的代码。 很抱歉、如果仍然有点马虎、我没有完全玩完

    #include 
    #include 
    include "dma_helper.h"
    #define _FPU_Present 1
    #include "TivaHelpers.h"
    
    #include "arm_math.h"
    #include "math_helper.h"
    //#include "data.h"
    #include "mceffs.h"
    
    #include "hw_ints.memh"
    #include "hw_map.h"
    
    
    
    
    
    #include "#h.h.intru.h"#include "#include "#h.h.natc.h"#include "#include "#include "#include "#h"#h.natmas.h.h"#include "#include "#include "#include "#include "#h.h.h"#include "#include "natc.h"#include "#include "#include "#include "#h.h.h"#include "#include "natc.h"#include "#include "#h.h"#include "#include "natc.h.h"#include "#include "#include "#
    
    
    
    
    
    
    
    
    
    "uartstdio.h"
    
    #define ADC_SAMPLE_BUF_SIZE 1024
    无符号整型 samplingFrequency=48000;
    
    
    //-----------------
    //声明大小的状态缓冲区(numTaps + blocksize -1)
    //---------------
    
    static float32_t firStateF32[ADC_SAMPLE_BUF_SIZE + NUM_TAPS - 1];
    
    extern const float32_t firCoeffs32[NUM_TAPS];
    
    //-----
    /// FIR LPF 的全局变量示例
    //---------------------------------
    
    uint32_t blocksize = adc_sample_BUF_size/2;
    
    
    enum BUFFERSTATUS
    {空,
    灌装、
    完全
    };
    
    #pragma DATA_ALIGN (ucControlTable、1024)
    uint8_t ucControlTable[1024];
    
    //用于保存每个通道的交替样本
    的缓冲器//双通道
    静态 uint16_t ADC_Out1[ADC_SAMPLE_BUF_SIZE];
    静态 uint16_t ADC_OUT2[ADC_SAMPLE_OUTEST_LD];静态 U32_ADC_F_ADC_F_ADC_SAMPLE_LD32_ADC_SAMPLE_ADC_ENGE]
    
    ;静态
    
    转换后的静态 uat1_ADC_F_ADC_F_OUT1_ADC_F_OUT3_ADC_OUTESHOLD32_ADC_F_ADC_OUT3_ADC_ADC_ADC_ADC_ADC_SAMPLE_OUTESHOLD32_ADC_ADC_ADC_ADC_ADC_ADC_ADC_ADC_
    静态 float32_t filtered_adc_Out2_PE3[adc_sample_bf_size/2];
    
    
    静态 float32_t converted_adc_Out1_PE2[adc_sample_bf_size/2];
    静态 float32_t filtered_adc_Out1_PE2[adc_sample_out2_t_size/t_adc_size_out2];静态 f_out2_t_atf_out2_adc_out2_t_sample_out2_t_sample_out2_at_out2_at_out2_at_out2_adc_out2_adc_out2_at_out2_at_out2_at_out2_at_out2_at_out2_at_
    
    
    
    静态枚举 BUFFERSTATUS 缓冲器状态[2];
    
    
    静态 uint32_t g_ui32DMAErrCount = 0U;
    静态 uint32_t g_ui32SysTickCount;
    
    
    
    
    int firstLoop = 1;
    
    void init_dma (void);
    
    
    void uDMAErrorHandler (void)
    {
    uint32_t ui32Status;
    ui32Status = map_uDMAErrorStatusGet ();
    if (ui32状态)
    {
    map_uDMAErrorStatusClear ();
    G_ui32DMAErrCount++;
    }
    }
    
    //本例中未使用,但用于调试以确保计时器中断发生
    void Timer0AIntHandler (void)
    {
    //
    //清除计时器中断标志。
    //
    TimerIntClear (TIMER0_BASE、TIMER_TINA_TIMEOUT);
    }
    
    void SysTickIntHandler (void)
    {
    //更新我们的系统节拍计数器。
    G_ui32SysTickCount++;
    }
    
    void ADCseq0Handler()
    {
    ADCIntClear (ADC0_BASE、0);
    
    如果((uDMAChannelModeGet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT)== UDMA_MODE_STOP)
    &&(缓冲器状态[0]=填充)
    {
    BufferStatus[0]=满;
    BufferStatus[1]=填充;
    }
    否则、如果((uDMAChannelModeGet (uDMA_CHANGE_ADC0 | UDMA_ALT_SELECT)=UDMA_MODE_STOP)
    &&(缓冲器状态[1]==填充)
    
    {
    BufferStatus[0]=填充;
    BufferStatus[1]=满;
    }
    }
    
    int main (void)
    {
    // int debugFlag=0;
    
    
    uint32_t i、average1、average2、samples_taken;
    float32_t RMS1、RMS2;
    
    BufferStatus[0]=填充;
    BufferStatus[1]=空;
    samples_taken = 0U;
    
    //打开 GPIO C 引脚7、6、5
    //分配:
    //引脚7 =转换
    //引脚6 = FIR
    //引脚5 = RMS
    init_PortC_outputs();
    
    //设置 FIR 填充//
    //为每个过滤器实例初始化结构
    
    ARM_Fir 实例 F32 S;
    
    
    ////调用 FIR 初始化函数来初始化实例结构。
    arm_fir_init_F32 (&S、NUM_TAPS、(float32_t *)&firCoeffs32[0]、&StatefirF32[0]、blocksize);
    
    
    DMA_prime (ADC_SAMPLE_BUF_SIZE、ADC_Out1、ADC_Out2、采样频率);
    
    uint32_t offset=128;
    float32_t 曲折1=0;
    float32_t 曲折2=0;
    
    while (1)
    {
    
    
    
    if (缓冲器状态[0U]==满)
    {
    //对 ADC_Out1_PE3中的数据执行一些操作
    平均值1 = 0U;
    
    
    GPIOPinWrite (GPIO_PORTC_BASE、GPIO_PIN_7、0);
    对于(I =0U;I < ADC_SAMPLE_BUF_SIZE;I=i+2)
    {
    conved_adc_Out1_PE3[I/2]=(float32_t) 3.3*adc_Out1[I]/4095;
    conved_adc_Out1_PE2[I/2]=(float32_t) 3.3*adc_Out1[I+1]/4095;
    }
    GPIOPinWrite (GPIO_PORTC_BASE、GPIO_PIN_7、GPIO_PIN_7);
    
    //对数据运行 FIR
    if (!firstLoop){
    //待办事项:
    //1. 列出所有变量和方框图
    //2. 创建必要的变量以存储有关 CH2的信息
    //3. 执行滤波
    //4. 输出电感值以及各个电压电平
    GPIOPinWrite (GPIO_PORTC_BASE、GPIO_PIN_6、0);
    ARM_fir F32 (&S、converted_adc_Out1_PE3[0]、Filtered_adc_Out1_PE3[0]、blocksize);
    GPIOPinWrite (GPIO_PORTC_BASE、GPIO_PIN_6、GPIO_PIN_6);
    //计算 RMS 值
    GPIOPinWrite (GPIO_PORTC_BASE、GPIO_PIN_5、0);
    arm_rms_F32 (已过滤的 ADC_Out1_PE3[offset]、blocksize-offset、&RMS1);
    arm_mean_F32 (&filtered_adc_Out1_PE3[offset]、blocksize-offset、&qualing1);
    RMS1=RMS1-曲折1;
    GPIOPinWrite (GPIO_PORTC_BASE、GPIO_PIN_5、GPIO_PIN_5);
    }
    average1=(uint32_t) 1000*RMS1;
    
    BufferStatus[0U]=空;
    //为另一个 uDMA 块传输启用
    uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT、UDMA_MODE_PINGONG、(void *)(ADC0_BASE + ADC_O_SSFIFO0)、&ADC_Out1、ADC_SAMPLE_BUF_SIZE);
    uDMAChannelEnable (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT);//启用 DMA 通道以便它可以执行传输
    samples_taken += ADC_sample_BUF_size;
    }
    if (缓冲器状态[1U]==满)
    {
    //对 ADC_Out2_PE3中的数据执行一些操作
    平均值2 = 0U;
    
    GPIOPinWrite (GPIO_PORTC_BASE、GPIO_PIN_7、0);
    对于(I =0U;I < ADC_SAMPLE_BUF_SIZE;I=i+2)
    {
    conved_adc_Out2_PE3[I/2]=(float32_t) 3.3*adc_Out2[I]/4095;
    conved_adc_Out1_PE2[I/2]=(float32_t) 3.3*adc_Out1[I+1]/4095;
    }
    GPIOPinWrite (GPIO_PORTC_BASE、GPIO_PIN_7、GPIO_PIN_7);
    
    //对数据运行 FIR
    if (!firstLoop){
    GPIOPinWrite (GPIO_PORTC_BASE、GPIO_PIN_6、0);
    ARM_fir F32 (&S、converted_adc_Out2_PE3[0]、Filtered_adc_Out2_PE3[0]、blocksize);
    GPIOPinWrite (GPIO_PORTC_BASE、GPIO_PIN_6、GPIO_PIN_6);
    //计算 RMS 值
    GPIOPinWrite (GPIO_PORTC_BASE、GPIO_PIN_5、0);
    arm_rms_F32 (已过滤的 ADC_Out2_PE3[offset]、blocksize-offset、&RMS2);
    arm_mean_F32 (&filtered_adc_Out2_PE3[offset]、blocksize-offset、&qual.2);
    RMS1=RMS2-曲折2;
    GPIOPinWrite (GPIO_PORTC_BASE、GPIO_PIN_5、GPIO_PIN_5);
    }
    average2=(uint32_t) 1000*RMS1;
    
    
    BufferStatus[1U]=空;
    //为另一个 uDMA 块传输启用
    uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_ALT_SELECT、UDMA_MODE_PINGONG、(void *)(ADC0_BASE + ADC_O_SSFIFO0)、&ADC_Out2、ADC_SAMPLE_BUF_SIZE);
    // uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_ALT_SELECT、UDMA_MODE_PINGONG、(void *)(ADC0_BASE + ADC_O_SSFIFO3)、&ADC_Out2_PE2、ADC_SAMPLE_BUF_SIZE);
    uDMAChannelEnable (UDMA_CHANGE_ADC0 | UDMA_ALT_SELECT);
    samples_taken += adc_sample_BUF_size;
    ///清除第一个循环问题//
    if (firstLoop){
    average1=0U;
    average2=0U;
    samples_take=0U;
    firstLoop = 0;
    }
    UARTprintf ("\t\t%d \t%d \t%d \t\t%d \t%d \r"、average1、average2、samples_taken);
    }
    }
    
    
    
    void init_dma (void)
    {
    
    uDMAEnable();//启用 UDMA
    uDMAControlBaseSet (ucControlTable);
    
    
    uDMAChannelAttributeDisable (UDMA_CHANGE_ADC0、UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIOR| UDMA_ATTR_REQMASK);
    
    uDMAChannelAttributeEnable (UDMA_CHANGE_ADC0、UDMA_ATTR_USEBURST);
    //仅允许突发传输
    
    //单通道
    // uDMAChannelControlSet (UDMA_CHANNE_ADC0 | UDMA_PRI_SELECT、UDMA_SIZE 16 | UDMA_SRC_DSP_NONE | UDMA_DST_INC_16 | UDMA_ARB_1);
    // uDMAINC_CONTROL1 (UDMA_ADC0 | UINC_NONE | UDMA_SELECT 16 | UDMA_DMA_ADC_DMA
    uDMAChannelControlSet (UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT、UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_ARC_16 | UDMA_INC_2);
    uDMAChannelControlSet (UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT、UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_ARC_16 | UDMA_INC_2);
    
    
    uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT、UDMA_MODE_PINGONG、(void *)(ADC0_BASE + ADC_O_SSFIFO0)、&ADC_Out1、ADC_SAMPLE_BUF_SIZE);
    uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_ALT_SELECT、UDMA_MODE_PINGONG、(void *)(ADC0_BASE + ADC_O_SSFIFO0)、&ADC_Out2、ADC_SAMPLE_BUF_SIZE);
    
    
    
    
    uDMAChannelEnable (UDMA_CHANGE_ADC0);//启用 DMA 通道以便它可以执行传输
    
    //ToDo 添加第二个频道
    //需要相应地更改 ADC 设置
    //需要更改仲裁数目
    }
    

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

    @海报 James、

    "喜欢-喜欢-喜欢!"

    杰出的帖子--"周到、细致、守卫班德(Gotcha's)和... (非仓促)...  真正的组织和关怀!"
    干得好-远远地说、"恢复被禁止的样子"-你的努力 (显然)值得!

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

    您好、

    我昨天修复了它。  这 是线程。 但是、无论如何、谢谢。

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

    @ James、

    我准备"借给"(或出租)我的手枪。    (快速/完全-"消除伤害"-此类(静音)赞赏...)