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.

[参考译文] TM4C129XNCZAD:DK-TM4C129 UDMA 和 ADC 设置

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/612982/tm4c129xnczad-dk-tm4c129-udma-and-adc-settings

器件型号:TM4C129XNCZAD

您好!

我花了很多时间来设置 UDMA、以便在 DK-TM4C129x 上与 ADC0配合使用。 论坛上的例子对我来说并不是很复杂,所以我决定分享我的经历。 希望这对他人有所帮助。

我的目标是:

  1. 设置 ADC0以在给定周期(转换由计时器触发)下进行五次测量(ADCSequence0);
  2. 设置 UDMA 以将 ADC 结果传输到两个缓冲器(乒乓模式)。 缓冲器是二维的、可以容纳30组测量。 如数组 A[30][5]:
    CH0结果 通道1结果 通道2结果 通道3结果 通道4结果
    转换#1 1 2. 3. 4. 5.
    转换#2 1 2. 3. 4. 5.
    (笑声)
    转换#30 1 2. 3. 4. 5.
  3. 当其中一个缓冲区已满时、产生 UDMA 中断、然后处理来自该缓冲区的数据。 同时、第二个缓冲区正在填充、当它已满时、会出现新中断、并且我会处理新数据。  

我用于执行该操作的代码部分:  

  1. 有些定义:  
    #define NUMBER_of_STEPS5// ADC0序列中的转换数0
    #define NUMBER_of_sets30//存储在缓冲区
    
    中的转换组数//用于存储 ADC 转换结果
    的缓冲区 int g_ui8RxBufA[NUMBER_of_SETs]、g_ui8RxBuf一系列 结果;[NUMBER_of_STEs]、g_Ui8RxBufSets[NUMBER_of_NOT_STEs];[NUMBER_of_SETs];[NUMBER_of_NOT_F] 

  2. ADC 设置:  
    //加电 ADC0
    SysCtlPeripheralEnable (SYSCTL_Periph_ADC0);
    
    //将 ADC 配置为在480MHz 时使用 PLL 除以24以获得20MHz 的 ADC 时钟。
    ADCClockConfigSet (ADC0_BASE、ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL、6);
    
    // GPIO 端口 E 和 K 需要启用
    SysCtlPeripheralEnable (SYSCTL_PERIPH_GPIOE);
    SysCtlPeripheralEnable (SYSCTL_PERIPH_GPIOK);
    
    //为这些模拟引脚选择 ADC 功能。
    GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_6);
    GPIOPinTypeADC (GPIO_PORTK_base、GPIO_PIN_0);
    
    //使用处理器信号触发器启用采样序列0。
    ADCSequenceConfigure (ADC0_BASE、0、ADC_TRIGGER_PROCESSOR、0);
    
    //配置序列上的步进。 在单端模式下对通道进行采样(默认)并在最后一次转换后配置中断标志
    ADCSequenceStepConfigure (ADC0_BASE、0、0、ADC_CTL_CH0 | ADC_CTL_SHOLD_4);
    ADCSequenceStepConfigure (ADC0_BASE、 0、1、ADC_CTL_CH1 | ADC_CTL_SHOLD_4);
    ADCSequenceStepConfigure (ADC0_BASE、0、 2、ADC_CTL_CH16 | ADC_CTL_shold_4);
    ADCSequenceStepConfigure (ADC0_BASE、0、3、 ADC_CTL_CH20 | ADC_CTL_shold_4);
    ADCSequenceStepConfigure (ADC0_BASE、0、4、ADC_CTL_TS | ADC_CTL_shold_4 | ADC_CTL_IE | ADC_CTL_END);
    
    //配置 ADC 的硬件过采样因子。
    ADCHardwareOversampleConfigure (ADC0_BASE、2);
    
    //在处理器上启用 ADC 序列0中断(NVIC)。
    IntEnable (INT_ADC0SS0);
    
    //为采样序列发生器启用 DMA。
    ADCSequenceDMAEnable (ADC0_BASE、0);
    
    //启用采样序列中断。
    ADCIntEnableEx (ADC0_BASE、ADC_INT_DMA_SS0);
    
    //由于采样序列0现已配置、因此必须将其启用。
    ADCSequenceEnable (ADC0_BASE、0);
    
    //清除中断状态标志。 这样做是为了确保在我们进行采样之前清除中断标志。
    ADCIntClear (ADC0_BASE、0);
    
    //触发 ADC 转换。
    ADCProcessorTrigger (ADC0_BASE、0); 

  3. 计时器设置:
    //配置定时器1
    SysCtlPeripheralEnable (SYSCTL_Periph_Timer1);
    
    TimerConfigure (Timer1_base、timer_CFG_PERIODICRAY);
    TimerLoadSet (Timer1_base、timer_A、 ui32SysClock /25000);
    IntEnable (INT_TIMER1A);
    TimerIntEnable (Timer1_base、timer_TINA_TIMEOUT);
    
    TimerEnable (Timer1_base、 Timer_A); 

  4. 定时器中断处理程序:
    void Timer1AIntHandler (void)
    {
    //清除计时器1中断标志
    TimerIntClear (Timer1_base、timer_TINA_TIMEOUT);
    
    //触发 ADC 转换
    ADCProcessorTrigger (ADC0_BASE、0);
    } 

  5. uDMA 设置:
    //加电 DMA
    SysCtlPeripheralReset (SYSCTL_Periph_UDMA);
    SysCtlPeripheralEnable (SYSCTL_Periph_UDMA);
    
    //启用 UDMA 控制器以供使用。
    uDMAEnable();
    
    uDMAControlBaseSet (pui8ControlTable);
    
    //将属性置于已知状态。 默认情况下应已禁用这些功能。
    uDMAChannelAttributeDisable (UDMA_CHANGE_ADC0、UDMA_ATTR_ALL);
    
    //设置 USEBURST 属性。 这比默认的允许单次或突发传输的总线使用更有效。
    uDMAChannelAttributeEnable (UDMA_CHANNE_ADC0、UDMA_ATTR_USEBURST);
    
    
    //为
    uDMAChannelControlSet (UDMA_CHANNE_ADC0 | UDMA_PRI_SELECT、
    UDMA_SIZE 32 | UDMA_DRC_DRC_NEL_32
    
    
    
    | UDAC_ADDRC_NEL_ADDRC_NE_32
    
    
    
    | UART_DRC_NE_DMA_TRUDB_DMA_TRIGN | UINC_NE_DMA_CONTRAL_ADAP_ADAP_DMA_TRUINC_NE_DMA_TRUINC_NE_ADAP_ADAP_ADAP_ADAP_ADAP_ADAP_D | UINC_NE_ADAP_ADAP_ADAP_TRUINC_NE_ADAP_ADAP_TRUINC_NE_ADAP_ADAP_ADAP_D | UINC_NE_ADAP_D_ADAP_ADAP_TRU 模式设置为乒乓
    uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT、UDMA_MODE_PINGONG、
    (void *)(ADC0_BASE + ADC_O_SSFIFO0)、
    g_ui8RxBufA、NUMBER_OF_SET * NUMBER_MAK_STOPPES
    
    、UDMA_TRANSDK_TANCE_DR_DR_DR_TRIPLE_DR_DRVE_TRIPLE_TRIPLE_TRIP_DR_DR_DRVEND0;
    (void *)(ADC0_BASE + ADC_O_SSFIFO0)、
    g_ui8RxBufB、NUMBER_OF_SET * NUMBER_OF_STEPS);
    
    ROM_uDMAChannelEnable (UDMA_CHANGE_ADC0); 

  6. uDMA 中断处理程序:
    void ADC0S0IntHandler (void)
    {
    uint16_t I = 0、j = 0;
    uint32_t intStatusEx = 0;
    uint32_t priChMode = 0;
    
    //获取中断状态
    intStatusALT = ADCIntStatusEx (ADC0_base、0);
    
    //获取通道
    DMA = UDAM_PRIM_0
    
    ;选择
    通道 UDAM_ODAM_SDK_CHANGE_DMA_SDK_MODE_0;选择通道 UDAM_OLUDMA_SDA_SDK_MODE_DAM_SDA_SDK_MODE_SDK_MODE_ADSDK_MODE_0;
    
    //清除中断标志
    ADCIntClearEx (ADC0_BASE、ADC_INT_DMA_SS0);
    
    //清除并重新初始化主 DMA 缓冲区(如果
    (priChMode = 0)
    {
    for (i = 0;i < number_of_steps;i++)
    {
    for (j = 0;j < number_of_rej];
    i =
    0[u+}设置}[fj+
    
    }
    uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT、UDMA_MODE_PINGONG、
    (void *)(ADC0_BASE + ADC_O_SSFIFO0)、
    g_ui8RxBufA、number_of_sets * number_of_steps);
    }
    
    //清除并重新初始化备用 DMA 缓冲器(
    如果它已满)(altChMode = 0)
    {
    for (i = 0;i < number_of_steps *=}
    
    
    
    uj;
    
    }ueltag+
    (transtag_u_deltag+);}[transtag_ueltag_u+(对于(transtag_u80+、}ueltag_u+、}[transtag_u+、}ueltag_u80+(transtag_u+、}ueltag_u_u_u_u_u80u_u_u_u&
    (void *)(ADC0_BASE + ADC_O_SSFIFO0)、
    g_ui8RxBufB、NUMBER_OF_SET * NUMBER_OF_STEPS);
    }
    

  7. 当然、不要忘记在矢量表中注册中断处理程序。

P.S. 这里是我在调试代码时遇到的一些奇怪的问题(我无法解释这些问题、但可能会对某人有所帮助):

  1. 第一个缓冲器加注错误。 我在 ADCSequence0和缓冲区中有5个步长,而不是像[1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 ...]这样的结果 我得到的结果是[1 2 3 4 5 5 5 5 5 5 5 5 5 5 5……]。 因此、在 ADC0 Sequence0 FIFO 结束后 DMA 缓冲区的填充不会停止。 这样、第一个缓冲器的填充速度非常快(在一个 ADC 转换期间内)。 但是第二个缓冲器被正确填充([1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 ...]])。
  2. 只有第二个(替代)缓冲器被填满。 函数 uDMAChannelModeGet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT)用于主缓冲区返回"0"(停止模式)并调用 uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT、UDMA_MODE_pingpong、(void *)(UDMA_CHANGE_ADC0 + UDMA_REF_0)。
  3. 设置中断的正确原因有点令人困惑。 因为我需要 uDMA 中断、但在 ADC0寄存器中启用它是必要的。

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

    尊敬的 Dennis:

    感谢您共享此实现方案。