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.

[参考译文] EK-TM4C123GXL:正确采样率的 ADC 设置

Guru**** 2524550 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/1161753/ek-tm4c123gxl-adc-setup-for-a-correct-samping-rate

器件型号:EK-TM4C123GXL

您好!

我想正确设置 ADC。
但我不理解数据表中的所有连接:
在数据表的第1389页可以找到以下数据:
-ADC 转换时钟频率= 16MHz
-ADC 转换率= 1Msps
-ADC 采样时间= 250ns
-ADC 转换时间= 1us
从触发到转换开始的延迟= 2个 ADC 时钟

这些数据是如何相关的?

我的硬件配置如下所示:

void init_SYS_CLOCK()
{
    MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | 
                       SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
    
    MAP_SysCtlDelay(10);
}

void init_WTIMER_5()
{
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER5);
    while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_WTIMER5));
    
    // WTimer 5A is PD6 and the trigger for adc
    MAP_TimerConfigure(WTIMER5_BASE, TIMER_CFG_SPLIT_PAIR | 
                       TIMER_CFG_A_PERIODIC);
    
    // Set ADC sampling frequency to be 44KHz every 22.725uS
    MAP_TimerLoadSet(WTIMER5_BASE, TIMER_A, (SysCtlClockGet()/44000) - 1);
    
    // Enable the ADC trigger output for Timer A.
    TimerControlTrigger(WTIMER5_BASE, TIMER_A, true);
    
    TimerEnable(WTIMER5_BASE, TIMER_A);
}

void init_uDMA_MIC0()
{
    // adc mic setup
    // uDMA Channel 14
    MAP_uDMAChannelAssign(UDMA_CH14_ADC0_0);
    
    MAP_uDMAChannelAttributeDisable(14,
                                    UDMA_ATTR_ALTSELECT | 
                                    UDMA_ATTR_HIGH_PRIORITY | 
                                    UDMA_ATTR_REQMASK);
    
    MAP_uDMAChannelControlSet(14 | UDMA_PRI_SELECT,
                              UDMA_SIZE_16 | UDMA_SRC_INC_NONE | 
                              UDMA_DST_INC_16 | UDMA_ARB_4);
    
    MAP_uDMAChannelControlSet(14 | UDMA_ALT_SELECT, 
                              UDMA_SIZE_16 | UDMA_SRC_INC_NONE | 
                              UDMA_DST_INC_16 | UDMA_ARB_4);
    
    MAP_uDMAChannelAttributeEnable(14, UDMA_ATTR_USEBURST);
}

void init_ADC0()
{
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0));
    
    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC | 
                      ADC_CLOCK_RATE_FULL, 1);
    
    SysCtlDelay(10);
}

void init_ADC0_MIC0()
{
    MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2);
    
    MAP_IntDisable(INT_ADC0SS0);
    MAP_ADCIntDisable(ADC0_BASE, 0);
    MAP_ADCSequenceDisable(ADC0_BASE, 0);
    
    //MAP_ADCHardwareOversampleConfigure(ADC0_BASE, 32);
    
    MAP_ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0);
    
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH5);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH5);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH5);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH5 | ADC_CTL_IE);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH5);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH5);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 0, 6, ADC_CTL_CH5);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 0, 7, ADC_CTL_CH5 | 
                                 ADC_CTL_IE | ADC_CTL_END);
    
    // ------------------ //
    // Priority Levels
    // Priority 4 = 0xE0 ->lower
    // Priority 3 = 0x60
    // Priority 2 = 0x20
    // Priority 1 = 0x00 ->higher
    // ------------------ //
    
    MAP_IntPrioritySet(INT_ADC0SS0, 0xE0); // Priority 4 !!!
}

void start_ADC0()
{
    recordMusic_ADC0();
    
    MAP_ADCSequenceEnable(ADC0_BASE, 0);
    MAP_ADCIntClear(ADC0_BASE, 0);
    MAP_ADCSequenceOverflowClear(ADC0_BASE, 0);
    MAP_ADCSequenceUnderflowClear(ADC0_BASE, 0);
    MAP_ADCSequenceDMAEnable(ADC0_BASE, 0);
    MAP_ADCIntEnable(ADC0_BASE, 0);
    MAP_IntEnable(INT_ADC0SS0);
}

void recordMusic_ADC0()
{
    #ifndef DEBUG_OFF
    DEBUG_PC4 = GPIO_PIN_4; // Rec
    #endif
    
    if (mic0BuffersStatus[0] == EMPTY)
    {
        // start primary channel to buffer in ADCBufferForFft0
        MAP_uDMAChannelTransferSet(14 | UDMA_PRI_SELECT, 
                                   UDMA_MODE_PINGPONG, 
                                   (void *)(ADC0_BASE + ADC_O_SSFIFO0), 
                                   &mic0Buffers[0], 1024);
        
        MAP_uDMAChannelEnable(14 | UDMA_PRI_SELECT);
        mic0BuffersStatus[0] = FILLING;
        
        #ifndef DEBUG_OFF
        DEBUG_PA2 = GPIO_PIN_2; // ADC Start Pri1
        #endif
    }
    
    if (mic0BuffersStatus[1] == EMPTY)
    {
        // start alternate channel to buffer in ADCBufferForFft1
        MAP_uDMAChannelTransferSet(14 | UDMA_ALT_SELECT, 
                                   UDMA_MODE_PINGPONG, 
                                   (void *)(ADC0_BASE + ADC_O_SSFIFO0), 
                                   &mic0Buffers[1], 1024);
        
        MAP_uDMAChannelEnable(14 | UDMA_ALT_SELECT);
        mic0BuffersStatus[1] = FILLING;
        
        #ifndef DEBUG_OFF
        DEBUG_PA3 = GPIO_PIN_3; // ADC Start Alt1
        #endif
    }
    
    #ifndef DEBUG_OFF
    DEBUG_PA2 = 0; // ADC Start Pri1
    DEBUG_PA3 = 0; // ADC Start Alt1
    #endif
}

80MHz 上的 CPU 时钟。
ADC 时钟频率为16MHz。
ADC 转换速率为1Msps。
WTimer5A 设置为44kHz。
如果硬件过采样关闭、如何立即计算采样率?
我想了解这种关系。
并且对一些计算示例也非常满意。

我刚刚使用 Logig Analyzer 检查了我的设置、发现计时器频率对采样率没有影响。
只有当我打开硬件过采样时、我才会获得低采样率。

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

    您好!

     如果您希望创建44Khz 的采样率、则最简单的方法是将计时器配置为44kHz。 我想您已经知道如何做到这一点。 对于 ADC 侧、您希望使用计时器作为触发源(ADC_TRIGGER_TIMER)、而不是像当前那样使用处理器触发器(ADC_TRIGGER_PROCESSORR)。  在这个设置中、定时器每44Khz 触发一次 ADC 采样。 转换后、ADC 生成 DMA 请求。 UDMA 将采样数据读取到缓冲器。 查看示例 C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c123gxl\adc_udma_pingpong、其中它使用计时器生成16kHz 采样率。 您可以参考此示例并将计时器超时更改为44Khz。  

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

    我在哪里使用  ADC_TRIGGER_PROCESSOR?

    我不明白当我用 ss0和7个步骤时、这是不起作用的。

    当我在 ss0中仅使用一个步骤时、它就可以正常工作。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [引用 userid="512790" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1161753/ek-tm4c123gxl-adc-setup-for-a-correct-samping-rate/4368987 #436987"]

    我在哪里使用  ADC_TRIGGER_PROCESSOR?

    [/报价]

    也许我误解了。 我曾经想到您有 ADC_TRIGGER_PROCESSOR. 但是、如果您具有如下所示的计时器触发器、则它是正确的。  

     ADCSequenceConfigure (ADC0_BASE、0、ADC_TRIGGER_TIMER、0);

    [引用 userid="512790" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1161753/ek-tm4c123gxl-adc-setup-for-a-correct-samping-rate/4368987 #4368987"]当我使用具有7个步骤的 ss0时,我无法理解这一点。

    什么不起作用?

    我看到您将 CH5连接到序列发生器0的八个步骤。 我假设您希望获取同一信道的八个样本、并可能在软件中计算平均值。 但是、我还看到您似乎只为缓冲区保留一个16位字、而不是为缓冲区阵列保留四个16位字。 这是你想要的吗? 我建议您在每个序列发生器的一个步长处保持简单、如示例、然后逐渐将步长数增加到2、3、3、... 以查看每个步进增量的影响。  

    MAP_uDMAChannelTransferSet (14 | UDMA_PRI_SELECT、
    UDMA_MODE_PINGONG、
    (void *)(ADC0_BASE + ADC_O_SSFIFO0)、
    &mic0Buffer[0]、1024);

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [引用 userid="93620" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1161753/ek-tm4c123gxl-adc-setup-for-a-correct-samping-rate/4369162 #4369162"]什么不起作用?

    我想以40kHz 的固定采样率保存1024个样本。
    这1024个样本将得到进一步处理。
    在此过程中、不得中断样本的记录。
    因此、我有2个缓冲器。
    uint16_t 微0缓冲器[2][1024];
    主 UDMA 通道和辅助 UDMA 通道应始终收集1024个数据。
    我想在 ADC0采样序列发生器处取0、因为它具有8个采样的 FIFO。
    同时处理更多数据时、UDMA 的工作效率更高。 我的意思是在突发模式下具有较高的仲裁大小。
    我的想法如下:
    让我通过 FIFO 收集前4个样本、然后在 UDMA 上提供中断。 以便一次传输4个样本、FIFO 可以继续在 FIFO 中的接下来4个样本中收集样本。 再说一次...
    但我在硬件中不会得到该设置。
    如果我用一个步骤配置采样序列发生器0并将 UDMA 的参数大小设置为1、那么它会起作用。
    但是、当我执行更多步骤时、1024个样本的记录时间会缩短。 为什么会这样呢?

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

    您好!

    [引用 userid="512790" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1161753/ek-tm4c123gxl-adc-setup-for-a-correct-samping-rate/4369498 #4369498">但一旦我执行更多步骤、1024个样本的记录时间将会缩短。 为什么会这样?

    我想原因是在每个计时器触发器中(您将其设置为44Khz)、您尝试获取8个样本而不是1个样本。  请记住、每次触发定时器时、它都会连续采集8个样本、这8个样本的采样率不是44Khz、而是您所拥有的任何 ADC 时钟速率(例如16MHz)。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [引用 userid="93620" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1161753/ek-tm4c123gxl-adc-setup-for-a-correct-samping-rate/4370612 #4370612"]我认为原因是在每个计时器触发器(您将其设置为44Khz)中,您尝试获取8个样本而不是1个样本。

    我已将其更改为序列。

    [引用 userid="93620" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1161753/ek-tm4c123gxl-adc-setup-for-a-correct-samping-rate/4370612 #4370612"]请记住、每次触发计时器时、它都会连续采集8个样本、这8个样本不是44Khz 速率、而是采用任何 ADC 时钟速率(例如16MHz)

    感谢您提供此信息。 现在、我还知道 ADC 转换时钟频率= 16MHz 时会执行什么操作。

    我还想使用硬件过采样。 但我还不明白该设置到底如何影响我的样本。
    我已使用我的配置将此 ADC 转换率= 1Msps 降至500ksps。 示例中显示了这种情况。
    如果我现在将硬件过采样设置为16、我将得到31.250sps。 这将低于我的计时器的40kHz 频率。 现在如何正确计算、尽管硬件过采样、我的样本仍记录在40kHz 的距离内?


    连接的麦克风可以测量20Khz。
    这意味着我不必再采样40kHz。
    是这样吗?

    我希望使用该计时器精确地对所有1024个样本进行采样。 此配置是否正确?

    EXTERN uint16_t mic0Buffers[2][1024];
    EXTERN volatile enum UDMA_TRANSFER_STATE mic0BuffersStatus[2];
    

    void init_SYS_CLOCK()
    {
        // 80Mhz Clock
        MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | 
                           SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
        
        MAP_SysCtlDelay(10);
    }

    void init_WTIMER_5()
    {
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER5);
        while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_WTIMER5));
        
        // WTimer 5A is PD6 and the trigger for adc
        MAP_TimerConfigure(WTIMER5_BASE, TIMER_CFG_SPLIT_PAIR | 
                           TIMER_CFG_A_PERIODIC);
        
        // set ADC sampling frequency to be 40KHz
        MAP_TimerLoadSet(WTIMER5_BASE, TIMER_A, 
                         (SysCtlClockGet()/40000) - 1);
        
        // enable the ADC trigger output for Timer A.
        TimerControlTrigger(WTIMER5_BASE, TIMER_A, true);
        
        TimerEnable(WTIMER5_BASE, TIMER_A);
    }

    void init_uDMA_MIC0()
    {
        // adc mic setup
        // uDMA Channel 14
        MAP_uDMAChannelAssign(UDMA_CH14_ADC0_0);
        
        MAP_uDMAChannelAttributeDisable(14,
                                        UDMA_ATTR_ALTSELECT | 
                                        UDMA_ATTR_HIGH_PRIORITY | 
                                        UDMA_ATTR_REQMASK);
        
        MAP_uDMAChannelControlSet(14 | UDMA_PRI_SELECT,
                                  UDMA_SIZE_16 | UDMA_SRC_INC_NONE | 
                                  UDMA_DST_INC_16 | UDMA_ARB_1);
        
        MAP_uDMAChannelControlSet(14 | UDMA_ALT_SELECT, 
                                  UDMA_SIZE_16 | UDMA_SRC_INC_NONE | 
                                  UDMA_DST_INC_16 | UDMA_ARB_1);
        
        MAP_uDMAChannelAttributeEnable(14, UDMA_ATTR_USEBURST);
    }

    void init_ADC0()
    {
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
        while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0));
        
        ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC | 
                          ADC_CLOCK_RATE_HALF, 1);
        
        SysCtlDelay(10);
    }

    void init_ADC0_MIC0()
    {
        MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2);
        
        MAP_IntDisable(INT_ADC0SS0);
        MAP_ADCIntDisable(ADC0_BASE, 0);
        MAP_ADCSequenceDisable(ADC0_BASE, 0);
        
        //MAP_ADCHardwareOversampleConfigure(ADC0_BASE, 16);
        MAP_ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0);
        
        MAP_ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH5 | ADC_CTL_IE | ADC_CTL_END);
        
        // ------------------ //
        // Priority Levels
        // Priority 4 = 0xE0 ->lower
        // Priority 3 = 0x60
        // Priority 2 = 0x20
        // Priority 1 = 0x00 ->higher
        // ------------------ //
        
        MAP_IntPrioritySet(INT_ADC0SS0, 0xE0); // Priority 4 !!!
    }

    void start_ADC0()
    {
        recordMusic_ADC0();
        
        MAP_ADCSequenceEnable(ADC0_BASE, 0);
        MAP_ADCIntClear(ADC0_BASE, 0);
        MAP_ADCSequenceOverflowClear(ADC0_BASE, 0);
        MAP_ADCSequenceUnderflowClear(ADC0_BASE, 0);
        MAP_ADCSequenceDMAEnable(ADC0_BASE, 0);
        MAP_ADCIntEnable(ADC0_BASE, 0);
        MAP_IntEnable(INT_ADC0SS0);
    }

    void recordMusic_ADC0()
    {
        if (mic0BuffersStatus[0] == EMPTY)
        {
            // start primary channel to buffer in ADCBufferForFft0
            MAP_uDMAChannelTransferSet(14 | UDMA_PRI_SELECT, 
                                       UDMA_MODE_PINGPONG, 
                                       (void *)(ADC0_BASE + ADC_O_SSFIFO0), 
                                       &mic0Buffers[0], 1024);
            
            MAP_uDMAChannelEnable(14 | UDMA_PRI_SELECT);
            mic0BuffersStatus[0] = FILLING;
        }
        
        if (mic0BuffersStatus[1] == EMPTY)
        {
            // start alternate channel to buffer in ADCBufferForFft1
            MAP_uDMAChannelTransferSet(14 | UDMA_ALT_SELECT, 
                                       UDMA_MODE_PINGPONG, 
                                       (void *)(ADC0_BASE + ADC_O_SSFIFO0), 
                                       &mic0Buffers[1], 1024);
            
            MAP_uDMAChannelEnable(14 | UDMA_ALT_SELECT);
            mic0BuffersStatus[1] = FILLING;
        }
    }

    void ADC0Seq0IntHandler(void)
    {
        ADCIntClear(ADC0_BASE, 0);
        
        if (uDMAChannelModeGet(14 | UDMA_PRI_SELECT) == UDMA_MODE_STOP)
        {
            mic0BuffersStatus[0] = FULL;
        }
        
        if (uDMAChannelModeGet(14 | UDMA_ALT_SELECT) == UDMA_MODE_STOP)
        {
            mic0BuffersStatus[1] = FULL;
        }
    }

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

    您好!

     您确定过采样是您想要的吗? 请参阅以下说明。 请看在输入信号上获取 A、B、C 和 D 样本。 假设您使用过采样、这些 A、B、C 和 D 将在44Khz 处获取。 是否要对这四个采样进行平均值计算? 如果您的输入信号是音乐信号、您是否要获取16个样本、然后对其求平均值。 以44Khz 的频率采集16个样本、然后对我来说、进行音乐采样是没有意义的。  我宁愿每44Khz 取一个样本。  无论如何,我认为16倍过采样是太多了。 这是您的应用、您应该知道最适合您的内容。 我可以对2倍或4倍的过采样进行镜像。 在这种情况下、您将设置计时器在44Khz x 2=88Khz 或44 x 44Khz x 4 = 176Khz 时触发。 在这些采样率下、您可以取2个或4个采样的平均值。  

    您需要的可能是您之前所拥有的。 您可以使用计时器以44Khz 的速率触发。 由于这8个采样在16MHz (1MSPS)时背靠背、因此每次触发将采集8个样本。 如果您真的认为采集多个样本会给您更好的保真度、那么对这8个样本求平均值。 在下一个触发器中、您对8个样本求平均值。