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/DK-TM4C129X:通过具有 DMA 的板级和#39;s ADC 对外部模拟信号进行采样

Guru**** 2479465 points


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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/695417/ccs-dk-tm4c129x-sampling-a-external-analog-signal-through-board-s-adc-with-dma

器件型号:DK-TM4C129X

工具/软件:Code Composer Studio

大家好!!!

我正在借助 ADC 以1MSPS 的速率通过 DMA 对外部模拟信号进行采样(由仲裁函数发生器进行)。 我正在使用乒乓技术来存储来自 AFE 的连续数据。 我将在电路板的 PE3/AIN0引脚上提供频率为1kHz 的正弦输入和幅值为1V 的正弦输入。 下面是我在 CCSv6上成功编译的完整代码。

#include 
#include 
include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_adc.h"
#include "inc/hw_types.h"
#include "inc/hw_udma.idr32_intrl"
#include "driverlib_driverlib_driverlib.idt.idr32"#include "driveript.inc/gui2_driverlib_uni32_intrature.id.id.inu.inc"





#include "driverlib_uni20_driverlib_driver32_driverlib"#driveript.id.id.id.id.inc"#def"inu.inu.inc/udpintrinu.id.inc"inu.inc"inu.id.inc"inu.id.id.id.id.inc"inu.id.inc"inu.inc"inu.inc"#def"#def"#def"intr.id/udpinu.inu.id.id.id.id.id.in















#define MEM_buffer_size 256

静态 uint32_t g_ui8RxBufA[MEM_buffer_size];

静态 uint32_t g_ui8RxBufB[MEM_buffer_size];

//*********

//

//! 

单端 ADC (single_ended)

//// ***************** void uDMAErrorHandler (void) { uint32_t ui32Status; // //检查 uDMA 错误位 // ui32Status = uDMAErrorStatusGet (); // //如果存在 uDMA 错误,则清除该错误并递增 //错误计数器。 // if (ui32状态) { uDMAErrorStatusClear(); } } void ADCseq0Handler() { uint32_t ui32Status; uint32_t ui32模式; ADCIntClearEx (ADC0_BASE、ADC_INT_DMA_SS3); ui32Mode = uDMAChannelModeGet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT); if (ui32Mode = uDMA_MODE_STOP) { uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT、 UDMA_MODE_PINGONG、 (void *)(ADC0_BASE + ADC_O_SSFIFO3)、 G_ui8RxBufA、MEM_buffer_size); uDMAChannelEnable (UDMA_CHANGE_ADC0); } ui32Mode = uDMAChannelModeGet (UDMA_CHANGE_ADC0 | UDMA_ALT_SELECT); if (ui32Mode = uDMA_MODE_STOP) { uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_ALT_SELECT、 UDMA_MODE_PINGONG、 (void *)(ADC0_BASE + ADC_O_SSFIFO3)、 G_ui8RxBufB、MEM_buffer_size); uDMAChannelEnable (UDMA_CHANGE_ADC0); } } 空 InitUART1传输(uint32_t sysclock) { uint32_t div; SysCtlPeripheralEnable (SYSCTL_Periph_ADC0); SysCtlPeripheralSlepEnable (SYSCTL_Periph_ADC0); ADCClockConfigSet (ADC0_BASE、ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL、1); // ADCClockConfigSet (ADC0_BASE、ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL、 30); SysCtlPeripheralEnable (SYSCTL_Periph_GPIOE); GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_3); //ADCSequenceConfigure (ADC0_BASE、0 /*SS0*/、ADC_TRIGGER_AYSHOW、3 /*Priority*/);// SS0-SS3优先级必须始终不同 ADCSequenceConfigure (ADC0_BASE、3、ADC_TRIGGER_PROCESSOR、0); ADCSequenceStepConfigure (ADC0_BASE、3、0、ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END); ADCSequenceEnable (ADC0_BASE、3); ADCSequenceDMAEnable (ADC0_BASE、3); uDMAChannelAttributeDisable (UDMA_CHANGE_ADC0、 UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIOR| UDMA_ATTR_REQMASK); uDMAChannelControlSet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT、 UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_DST_INC_32 | UDMA_NEW_USEBURST | UDMA_ARB_256); uDMAChannelControlSet (UDMA_CHANGE_ADC0 | UDMA_ALT_SELECT、 UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_DST_INC_32 | UDMA_NEW_USEBURST | UDMA_ARB_256); uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT、 UDMA_MODE_PINGONG、 (void *)(ADC0_BASE + ADC_O_SSFIFO3)、 G_ui8RxBufA、MEM_buffer_size); uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_ALT_SELECT、 UDMA_MODE_PINGONG、 (void *)(ADC0_BASE + ADC_O_SSFIFO3)、 G_ui8RxBufB、MEM_buffer_size); uDMAChannelEnable (UDMA_CHANGE_ADC0); ADCIntEnableEx (ADC0_BASE、ADC_INT_DMA_SS3); IntEnable (INT_ADC0SS3); } int main (void) { uint32_t sysclock; SysClock = SysCtlClockFreqSet ((SYSCTL_XTAL_25MHz | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480)、20000000); SysCtlPeripheralEnable (SYSCTL_Periph_UDMA); SysCtlPeripheralSlepEnable (SYSCTL_Periph_UDMA); IntMasterEnable(); IntEnable (INT_UDMAERR); uDMAEnable(); uDMAControlBaseSet (pui8ControlTable); InitUART1传输(sysclock); while (1) { } }

它在编译时没有任何错误、但输出(g_ui8RxBufA)的所有值都为0。 我无法确定代码有什么问题。

谢谢你

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您在 ADCSequenceConfigure (ADC0_BASE、3、ADC_TRIGGER_PROCESSORE、0)中指定处理器触发器、但我看不到您向 ADC 模块生成处理器触发器。 我建议您先确保 ADC 在没有 UDMA 的情况下工作、然后在 ADC 工作后、您可以集成 UDMA。

    另外、为什么要使用处理器触发器?您可能需要考虑使用计时器作为触发器。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Charles、很抱歉我迟到了。 我考虑使用计时器来触发 ADC。 这是修改后的代码。 当我运行它时,它进入 IntDefaultHandler()无限循环。  

    #include 
    #include 
    include "inc/hw_ints.h"
    #include "volatile inc/hw_memmap.h"
    #include "inc/hw_adc.h"
    #include "inc/hw_types.h"
    #include "inc/hw_udma.idrave2_driverlib"
    
    
    
    
    
    
    #include "driverlib/driverlib.driver32.driverlib"#driveript/driverlib_driveript.driverlib#include "driverlib_driver32.driverlib_driveript/driveript.id.id.inc.id.inc"#include "#driverlib_driveript/driverlib_driver32.driveript/gui_driverlib.inc.id.id.id.id.inc"#include "driveript.inc.inc.inc.inc.id.id.inc.id.inc.id.id.inc.id.id.inc.id.idr.idr.idr.idr32_driveript.id.id.in.id.id.id.id.id.id
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    #define MEM_buffer_size 256
    
    静态 uint32_t g_ui8RxBufA[MEM_buffer_size];
    
    静态 uint32_t g_ui8RxBufB[MEM_buffer_size];
    
    //*********
    
    //
    
    //! 

    单端 ADC (single_ended)

    //// ***************** void uDMAErrorHandler (void) { uint32_t ui32Status; // //检查 uDMA 错误位 // ui32Status = uDMAErrorStatusGet (); // //如果存在 uDMA 错误,则清除该错误并递增 //错误计数器。 // if (ui32状态) { uDMAErrorStatusClear(); } } void ADCseq0Handler() { //uint32_t ui32Status; uint32_t ui32模式; ADCIntClearEx (ADC0_BASE、ADC_INT_DMA_SS3); ui32Mode = uDMAChannelModeGet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT); if (ui32Mode = uDMA_MODE_STOP) { uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT、 UDMA_MODE_PINGONG、 (void *)(ADC0_BASE + ADC_O_SSFIFO3)、 G_ui8RxBufA、MEM_buffer_size); uDMAChannelEnable (UDMA_CHANGE_ADC0); } ui32Mode = uDMAChannelModeGet (UDMA_CHANGE_ADC0 | UDMA_ALT_SELECT); if (ui32Mode = uDMA_MODE_STOP) { uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_ALT_SELECT、 UDMA_MODE_PINGONG、 (void *)(ADC0_BASE + ADC_O_SSFIFO3)、 G_ui8RxBufB、MEM_buffer_size); uDMAChannelEnable (UDMA_CHANGE_ADC0); } } 空 InitUART1传输(uint32_t sysclock) { //uint32_t div; SysCtlPeripheralEnable (SYSCTL_Periph_ADC0); while (!(SysCtlPeripheralReady (SYSCTL_Periph_ADC0))); SysCtlPeripheralSlepEnable (SYSCTL_Periph_ADC0); ADCClockConfigSet (ADC0_BASE、ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL、1); // ADCClockConfigSet (ADC0_BASE、ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL、 30); SysCtlPeripheralEnable (SYSCTL_Periph_GPIOE); while (!(SysCtlPeripheralReady (SYSCTL_Periph_GPIOE))); GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_3); //ADCSequenceConfigure (ADC0_BASE、0 /*SS0*/、ADC_TRIGGER_AYSHOW、3 /*Priority*/);// SS0-SS3优先级必须始终不同 ADCSequenceConfigure (ADC0_BASE、3、ADC_TRIGGER_TIMER、0); ADCSequenceStepConfigure (ADC0_BASE、3、0、ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END); ADCSequenceEnable (ADC0_BASE、3); ADCIntClear (ADC0_BASE、3); //启用计时器外设 SysCtlPeripheralEnable (SYSCTL_Periph_TIMER0); //计时器应定期运行 TimerConfigure (TIMER0_BASE、TIMER_CFG_PERIODICASE); //设置每次计时器完成时加载到计时器中的值 //这是计时器触发 ADC 之前所需的时钟周期数 #define F_sample 1000 TimerLoadSet (TIMER0_BASE、TIMER_A、SYSCLOCK /F_SAMPLE); //启用触发 TimerControlTrigger (TIMER0_BASE、TIMER_A、TRUE); ADCIntEnable (ADC0_BASE、2); //启用计时器 TimerEnable (TIMER0_BASE、TIMER_A); ADCSequenceDMAEnable (ADC0_BASE、3); uDMAChannelAttributeDisable (UDMA_CHANGE_ADC0、 UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIOR| UDMA_ATTR_REQMASK); uDMAChannelControlSet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT、 UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_DST_INC_32 | UDMA_NEW_USEBURST | UDMA_ARB_256); uDMAChannelControlSet (UDMA_CHANGE_ADC0 | UDMA_ALT_SELECT、 UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_DST_INC_32 | UDMA_NEW_USEBURST | UDMA_ARB_256); uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_PRI_SELECT、 UDMA_MODE_PINGONG、 (void *)(ADC0_BASE + ADC_O_SSFIFO3)、 G_ui8RxBufA、MEM_buffer_size); uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | UDMA_ALT_SELECT、 UDMA_MODE_PINGONG、 (void *)(ADC0_BASE + ADC_O_SSFIFO3)、 G_ui8RxBufB、MEM_buffer_size); uDMAChannelEnable (UDMA_CHANGE_ADC0); ADCIntEnableEx (ADC0_BASE、ADC_INT_DMA_SS3); IntEnable (INT_ADC0SS3); } int main (void) { uint32_t sysclock; SysClock = SysCtlClockFreqSet ((SYSCTL_XTAL_25MHz | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480)、120000000); SysCtlPeripheralEnable (SYSCTL_Periph_UDMA); while (!(SysCtlPeripheralReady (SYSCTL_Periph_UDMA))); SysCtlPeripheralSlepEnable (SYSCTL_Periph_UDMA); IntMasterEnable(); IntEnable (INT_UDMAERR); uDMAEnable(); uDMAControlBaseSet (pui8ControlTable); InitUART1传输(sysclock); while (1) { } }

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我建议您在没有 UDMA 的情况下尝试使用 ADC。 您是否有机会做到这一点并确保它首先起作用?

    如果您获得 IntDefaultHandler、则意味着您没有中断处理程序。 我看到您创建的 uDMAErrorHandler 和 ADCseq0Handler。 但是、您是否在 startup_ccs.c 文件的矢量表中添加了这些矢量表?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    很抱歉,我忘记了前面提到。 ADC 工作正常。 你是对的。 我没有将它们添加到启动文件中的矢量表中。 我现在在 ADC 序列0处添加了 ADCseq0Handler、在 UDMA 错误处添加了 uDMAErrorHandler。 但是、当我运行代码时、它仍然停留在 IntDefaultHandler 中。 这里是我的主源文件和启动文件。

    e2e.ti.com/.../single_5F00_ended.c

    e2e.ti.com/.../7457.tm4c1294nczad_5F00_startup_5F00_ccs.c

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

    您好 Charles、在我的代码中、如果我将序列发生器从3更改为0、只需修改某些部分、代码就可以正常工作并提供几乎正确的输出。 它不会进入 SS0的 IntDefaultHandler 循环。 几乎正确、如所示、如果我从函数发生器提供方波作为输入、我会在缓冲器中得到某种失真波。 为什么会出现这种问题、因为如果我使用序列0、它工作正常、但如果我使用序列3、它不工作?

    更新了代码:

    e2e.ti.com/.../7080.single_5F00_ended.c

    此致、

    Harshul

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    矢量表、如下所示。 您将 ADCseq0Handler 放置在与 ADC0序列相对应的位置、但在您的应用程序中、您将为序列3进行配置。 您只需通过将 ADCseq0Handler 移动到 ADC0序列3来修复启动文件、该文件就可以正常工作了。

    ADCseq0Handler、// ADC 序列0
    IntDefaultHandler、 // ADC 序列1
    IntDefaultHandler、 // ADC 序列2.
    IntDefaultHandler、 // ADC 序列3.
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    是的、查尔斯、你说得对。 我进行了更改、代码工作正常。 我仍有疑问。 我想澄清一下这件事。 我的系统时钟频率设置为120MHz、我以计时器转换率加载1000以获得计时器加载值120kHz、并将采样数增加到1024。 因此、这意味着在计时器每1000个时钟周期后、它会触发 ADC 一次。 现在、g_ui8RxBufA 缓冲区的长度为1024、因此使该缓冲区填满所需的时间变为1024/120000。 我的采样率是120kHz。 我是对的吗? 因为如果采样率为120kHz、那么我的输入模拟正弦信号的频率应小于或等于60kHz、以满足奈奎斯特标准、从而避免混叠。 但是、当我给出幅值为1Vpp 和200kHz 频率和0.5V 偏移的正弦波并绘制 g_ui8RxBufA 缓冲器值时、结果是正确的正弦波。 因此、不应发生这种情况。 内部实际发生了什么、您能澄清一下并分享您的想法吗?

    此致、
    Harshul
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    当您将 PIOSC 指定为 ADC 的时钟源时、ADC 源时钟为16MHz。 ADC 具有12位分辨率。 这意味着在对 AINx 输入进行采样并将电荷耦合到内部电容器之后、需要12个 ADC 时钟周期来完成转换。 最小采样/保持时间为4个周期。 因此、完成一个 ADC 通道转换需要16个周期。 ADC 时钟频率为16MHz 时、最大采样率为(16MHz/16) 1MSPS。 要获得1MSPS 速率、您需要将计时器设置为1MHz 速率、以触发转换、而不是120kHz。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢 Charles 的澄清。

    此致、

    Harshul