请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
器件型号:TM4C129XNCZAD 您好!
我花了很多时间来设置 UDMA、以便在 DK-TM4C129x 上与 ADC0配合使用。 论坛上的例子对我来说并不是很复杂,所以我决定分享我的经历。 希望这对他人有所帮助。
我的目标是:
- 设置 ADC0以在给定周期(转换由计时器触发)下进行五次测量(ADCSequence0);
- 设置 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. - 当其中一个缓冲区已满时、产生 UDMA 中断、然后处理来自该缓冲区的数据。 同时、第二个缓冲区正在填充、当它已满时、会出现新中断、并且我会处理新数据。
我用于执行该操作的代码部分:
- 有些定义:
#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]
- 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);
- 计时器设置:
//配置定时器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);
- 定时器中断处理程序:
void Timer1AIntHandler (void) { //清除计时器1中断标志 TimerIntClear (Timer1_base、timer_TINA_TIMEOUT); //触发 ADC 转换 ADCProcessorTrigger (ADC0_BASE、0); }
- 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);
- 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); }
- 当然、不要忘记在矢量表中注册中断处理程序。
P.S. 这里是我在调试代码时遇到的一些奇怪的问题(我无法解释这些问题、但可能会对某人有所帮助):
- 第一个缓冲器加注错误。 我在 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 ...]])。
- 只有第二个(替代)缓冲器被填满。 函数 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)。
- 设置中断的正确原因有点令人困惑。 因为我需要 uDMA 中断、但在 ADC0寄存器中启用它是必要的。