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.

F28335 ePWM AD频率设置问题

使用ePWM事件触发方式启动AD转换,转换频率为6M,请问该怎么设置啊,自己按照官网的例程修改的程序EPwm1Regs.CMPA.half.CMPA = 6; 

EPwm1Regs.TBPRD = 12,用示波器量出来只有212KHz,请问是什么原因,初始化程序如下:

EALLOW;
SysCtrlRegs.HISPCP.all = ADC_MODCLK; // HSPCLK = SYSCLKOUT/ADC_MODCLK
EDIS;

//--- Peripheral Initialization
InitAdc();// Initialize the ADC (FILE: Adc.c)

// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
EALLOW; // This is needed to write to EALLOW protected register
PieVectTable.ADCINT = &adc_isr;
EDIS;// This is needed to disable write to EALLOW protected registers

AdcRegs.ADCTRL1.bit.ACQ_PS = ADC_SHCLK;
AdcRegs.ADCTRL3.bit.ADCCLKPS = ADC_CKPS;

AdcRegs.ADCTRL1.bit.SEQ_CASC = 1;

AdcRegs.ADCTRL3.bit.SMODE_SEL = 0;


AdcRegs.ADCTRL1.bit.CONT_RUN = 0;
// Enable Sequencer override feature
AdcRegs.ADCTRL1.bit.SEQ_OVRD = 1;
// Initialize all ADC channel selects to A0
AdcRegs.ADCCHSELSEQ1.all = 0x0;
AdcRegs.ADCCHSELSEQ2.all = 0x0;
AdcRegs.ADCCHSELSEQ3.all = 0x0;
AdcRegs.ADCCHSELSEQ4.all = 0x0;

AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0;

AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 0;

AdcRegs.ADCTRL2.bit.EPWM_SOCA_SEQ1 = 1;// Enable SOCA from ePWM to start SEQ1

AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1; // Enable SEQ1 interrupt (every EOS)


EPwm1Regs.ETSEL.bit.SOCAEN = 1; // Enable SOC on A group

EPwm1Regs.ETSEL.bit.SOCASEL = 4; // Select SOC from from CPMA on upcount

EPwm1Regs.ETPS.bit.SOCAPRD = 1; // Generate pulse on 1st event

EPwm1Regs.CMPA.half.CMPA = 6; // Set compare A value

EPwm1Regs.TBPRD = 12; // Set period for ePWM1

EPwm1Regs.TBCTL.bit.CTRMODE = 0; // count up and start

// Enable ADCINT in PIE
PieCtrlRegs.PIEIER1.bit.INTx6 = 1;
IER |= M_INT1; // Enable CPU Interrupt 1
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM

  • Feng Youkui Feng Youkui 说:

    EPwm1Regs.CMPA.half.CMPA = 6; 

    EPwm1Regs.TBPRD = 12,用示波器量出来只有212KHz,请问是什么原因,初始化程序如下:

    212kHz具体测量的是什么信号的频率?下面的其它配置里修改部分参数会怎样?

    Feng Youkui Feng Youkui 说:

    EALLOW;
    SysCtrlRegs.HISPCP.all = ADC_MODCLK; // HSPCLK = SYSCLKOUT/ADC_MODCLK
    EDIS;

    //--- Peripheral Initialization
    InitAdc();// Initialize the ADC (FILE: Adc.c)

    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
    EALLOW; // This is needed to write to EALLOW protected register
    PieVectTable.ADCINT = &adc_isr;
    EDIS;// This is needed to disable write to EALLOW protected registers

    AdcRegs.ADCTRL1.bit.ACQ_PS = ADC_SHCLK;
    AdcRegs.ADCTRL3.bit.ADCCLKPS = ADC_CKPS;

    这里的ADC_MODCLK,ADC_SHCLK,ADC_CKPS宏定义的值具体是多少?

    如果

    EPwm1Regs.ETSEL.bit.SOCAEN = 1;

    改成

    EPwm1Regs.ETSEL.bit.SOCAEN = 0;

    会怎样?

  • 212kHz具体测量的是进入中断后在中断函数里翻转GPIO口 用示波器测量得到的 2*106KHz

    #if (CPU_FRQ_150MHZ) // Default - 150 MHz SYSCLKOUT
    #define ADC_MODCLK 0x3 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3) = 25.0 MHz
    #endif

    #define ADC_CKPS 0x0 // ADC module clock = HSPCLK/1 = 25.5MHz/(1) = 25.0 MHz
    #define ADC_SHCLK 0x1 // S/H width in ADC module periods

    EPwm1Regs.ETSEL.bit.SOCAEN = 1;

    改成

    EPwm1Regs.ETSEL.bit.SOCAEN = 0;后不能正常进入adc_isr中断函数

  • 所以你是在每次ADC转换后进入ADC中断?这样看,你的程序设计可能存在问题,因为你的采样时间设置的太短(ADCCLK=25MHz, ACQ_PS=1),也就是每个信号仅用时2个时钟,即80ns,达到最高的12.5MHz的采样速度,这个本身是没有问题的,因为F28335的ADC模块支持这么高的转换速度,但是,你每次只采样一个信号(MAX_CONV1 = 0),然后每次都进入中断(INT_ENA_SEQ1 = 1),这个是CPU处理不过来的:80ns/6.67ns=12,也就是要求中断必须在12个指令周期内完成 -- 这显然是不可能的:参考下面内容,进入中断进行现场保护就至少需要16个时钟,更何况你还需要处理数据,清除标志位等等。

    http://processors.wiki.ti.com/index.php/Interrupt_FAQ_for_C2000#ISR_Latency

    建议你可以调整方式测试一下,比如多采样几个通道,或者增大采样窗口,或者稍微调低转换速度,或者每两次转换进一次中断等等(根据上方括号里引用的配置简单修改即可),而在实际应用场景里,通常都是采样多个信号后产生一次中断,进行数据读取,因此既可以达到12.5MH在的采样速度,也不会影响数据的处理。

    最后,既然你也配置了级联模式(SEQ_CASC = 1),为什么不多采样几个信号呢?

  • 请问AN0引脚采样2M的输入信号 程序该如何编写?根据采样定理需要大于2倍的采样速率才可以 也就是说AD采样要达到4M,这要怎么设置呢?

  • 上面提到,采样速度达到12.5MHz都没有问题呀,关键是你不能每次都进中断,因为CPU响应不过来。

    请仔细阅读并理解我上面的分析,将ADC采样转换和CPU执行中断代码这两件事情分开,你就不会困惑了。

  • 如果用查询方式 如何确定采样频率?如下面的程序如何确定采样频率是多少???

    #include "DSP28x_Project.h" // Device Headerfile and Examples Include File

    // Determine when the shift to right justify the data takes place
    // Only one of these should be defined as 1.
    // The other two should be defined as 0.
    #define POST_SHIFT 0 // Shift results after the entire sample table is full
    #define INLINE_SHIFT 1 // Shift results as the data is taken from the results regsiter
    #define NO_SHIFT 0 // Do not shift the results

    // ADC start parameters
    #if (CPU_FRQ_150MHZ) // Default - 150 MHz SYSCLKOUT
    #define ADC_MODCLK 0x3 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3) = 25.0 MHz
    #endif
    #if (CPU_FRQ_100MHZ)
    #define ADC_MODCLK 0x2 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 100/(2*2) = 25.0 MHz
    #endif
    #define ADC_CKPS 0x0 // ADC module clock = HSPCLK/1 = 25.5MHz/(1) = 25.0 MHz
    #define ADC_SHCLK 16 // S/H width in ADC module periods = 2 ADC cycle
    #define AVG 1000 // Average sample limit
    #define ZOFFSET 0x00 // Average Zero offset
    #define BUF_SIZE 1024 // Sample buffer size

    // Global variable for this example
    Uint16 SampleTable[BUF_SIZE];

    main()
    {
    Uint16 i;
    Uint16 array_index;

    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the DSP2833x_SysCtrl.c file.
    InitSysCtrl();

    // Specific clock setting for this example:
    EALLOW;
    SysCtrlRegs.HISPCP.all = ADC_MODCLK; // HSPCLK = SYSCLKOUT/ADC_MODCLK
    EDIS;

    // Step 2. Initialize GPIO:
    // This example function is found in the DSP2833x_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    // InitGpio(); // Skipped for this example
    // Enable the pin GPIO34 as output
    EALLOW;
    GpioCtrlRegs.GPBMUX1.bit.GPIO34 = 0; // GPIO pin
    GpioCtrlRegs.GPBDIR.bit.GPIO34 = 1; // Output pin
    EDIS;

    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
    DINT;

    // Initialize the PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the DSP2833x_PieCtrl.c file.
    InitPieCtrl();

    // Disable CPU interrupts and clear all CPU interrupt flags:
    IER = 0x0000;
    IFR = 0x0000;

    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example. This is useful for debug purposes.
    // The shell ISR routines are found in DSP2833x_DefaultIsr.c.
    // This function is found in DSP2833x_PieVect.c.
    InitPieVectTable();

    // Step 4. Initialize all the Device Peripherals:
    // This function is found in DSP2833x_InitPeripherals.c
    // InitPeripherals(); // Not required for this example
    InitAdc(); // For this example, init the ADC

    // Specific ADC setup for this example:
    AdcRegs.ADCTRL1.bit.ACQ_PS = ADC_SHCLK; // Sequential mode: Sample rate = 1/[(2+ACQ_PS)*ADC clock in ns]
    // = 1/(3*40ns) =8.3MHz (for 150 MHz SYSCLKOUT)
    // = 1/(3*80ns) =4.17MHz (for 100 MHz SYSCLKOUT)
    // If Simultaneous mode enabled: Sample rate = 1/[(3+ACQ_PS)*ADC clock in ns]
    AdcRegs.ADCTRL3.bit.ADCCLKPS = ADC_CKPS;
    AdcRegs.ADCTRL1.bit.SEQ_CASC = 1; // 1 Cascaded mode
    AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0;
    AdcRegs.ADCTRL1.bit.CONT_RUN = 1; // Setup continuous run

    AdcRegs.ADCTRL1.bit.SEQ_OVRD = 1; // Enable Sequencer override feature
    AdcRegs.ADCCHSELSEQ1.all = 0x0; // Initialize all ADC channel selects to A0
    AdcRegs.ADCCHSELSEQ2.all = 0x0;
    AdcRegs.ADCCHSELSEQ3.all = 0x0;
    AdcRegs.ADCCHSELSEQ4.all = 0x0;
    AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 0x7; // convert and store in 8 results registers

    // Step 5. User specific code, enable interrupts:

    // Clear SampleTable
    for (i=0; i<BUF_SIZE; i++)
    {
    SampleTable[i] = 0;
    }

    // Start SEQ1
    AdcRegs.ADCTRL2.all = 0x2000;

    for(;;)
    { // Take ADC data and log them in SampleTable array

    // Initialize the array index. This points to the current
    // location within the SampleTable
    array_index = 0;

    for (i=0; i<(BUF_SIZE/16); i++)
    {
    // Wait for int1
    while (AdcRegs.ADCST.bit.INT_SEQ1== 0){}
    GpioDataRegs.GPBSET.bit.GPIO34 = 1; // Set GPIO34 for monitoring -optional

    AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;

    #if INLINE_SHIFT
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT0)>>4);
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT1)>>4);
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT2)>>4);
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT3)>>4);
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT4)>>4);
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT5)>>4);
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT6)>>4);
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT7)>>4);

    #endif //-- INLINE_SHIFT

    #if NO_SHIFT || POST_SHIFT

    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT0));
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT1));
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT2));
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT3));
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT4));
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT5));
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT6));
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT7));

    #endif //-- NO_SHIFT || POST_SHIFT

    while (AdcRegs.ADCST.bit.INT_SEQ1== 0){}
    GpioDataRegs.GPBCLEAR.bit.GPIO34 = 1; // Clear GPIO34 for monitoring -optional
    AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;

    #if INLINE_SHIFT

    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT8)>>4);
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT9)>>4);
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT10)>>4);
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT11)>>4);
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT12)>>4);
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT13)>>4);
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT14)>>4);
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT15)>>4);

    #endif //-- INLINE_SHIFT

    #if NO_SHIFT || POST_SHIFT

    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT8));
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT9));
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT10));
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT11));
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT12));
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT13));
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT14));
    SampleTable[array_index++]= ( (AdcRegs.ADCRESULT15));
    #endif // -- NO_SHIFT || POST_SHIFT

    }


    #if POST_SHIFT
    // For post shifting, shift the ADC results
    // in the SampleTable buffer after the buffer is full.
    for (i=0; i<BUF_SIZE; i++)
    {
    SampleTable[i] = ((SampleTable[i]) >>4);
    }
    #endif // -- POST_SHIFT

    GpioDataRegs.GPBCLEAR.bit.GPIO34 = 1; // Clear GPIO34 for monitoring -optional
    }
    }

  • 采样或转换频率与是否使用查询或中断方式无关。

    采样频率是你设定用于触发SEQ的频率,也就是EPWM的SOCA产生的频率,即每隔多长时间让ADC进行一次采样和转换。

    转换速度通常说的是每次采样和转换所需要的时间,这个跟ADCCLK有关,跟采样窗口大小有关。如我之前回复的,ADCCLK=25MHz,ACQ_PS=1时,这个时间是80ns ((1+1)/25MHz).

    可以参考早些时候的相关讨论。

    http://www.deyisupport.com/question_answer/microcontrollers/c2000/f/56/p/25637/86547.aspx#86547

  • 如果使用连续转换 是不是采样速率等于转换频率?

    如果 

    HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3)   = 25.0 MHz

    AdcRegs.ADCTRL1.bit.ACQ_PS = 15;

    AdcRegs.ADCTRL1.bit.CPS = 0; 

    AdcRegs.ADCTRL3.bit.ADCCLKPS =15;

    那么转换时间是(15+1)/(25MHz/(30+1))=19.84us 频率就是1/19.84us=50.40KHz

    采样的频率也是50.40KHz  这样理解对吗?

  • Feng Youkui Feng Youkui 说:

    如果使用连续转换 是不是采样速率等于转换频率?

    对。连续采样建议使用软件和硬件触发第一次采样,然后第一次采样的EOC产生中断,由中断触发后面的SEQ.

    Feng Youkui Feng Youkui 说:

    如果 

    HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3)   = 25.0 MHz

    AdcRegs.ADCTRL1.bit.ACQ_PS = 15;

    AdcRegs.ADCTRL1.bit.CPS = 0; 

    AdcRegs.ADCTRL3.bit.ADCCLKPS =15;

    那么转换时间是(15+1)/(25MHz/(30+1))=19.84us 频率就是1/19.84us=50.40KHz

    采样的频率也是50.40KHz  这样理解对吗?

    有点小错误,请参考ADC用户手册的1.4.1 ADC-module Clock and Sample Rate章节进行计算。

    (15+1)/(25MHz/(30*(0+1)))=18us,也就是55.5kHz.

  • 如果使用查询方式 采样频率是否可以达到12.5M,主要担心程序在flash中的执行时间没有那么快,如果达不到改怎么处理才可以达到12.5M, 程序如下

    AdcRegs.ADCTRL1.bit.ACQ_PS = 0; // Sequential mode: Sample rate = 1/[(2+ACQ_PS)*ADC clock in ns]
    // = 1/(3*40ns) =8.3MHz (for 150 MHz SYSCLKOUT)
    // = 1/(3*80ns) =4.17MHz (for 100 MHz SYSCLKOUT)
    // If Simultaneous mode enabled: Sample rate = 1/[(3+ACQ_PS)*ADC clock in ns]
    AdcRegs.ADCTRL3.bit.ADCCLKPS = 0;
    AdcRegs.ADCTRL1.bit.SEQ_CASC = 1; // 1 Cascaded mode
    AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0;
    AdcRegs.ADCTRL1.bit.CONT_RUN = 1; // Setup continuous run

    AdcRegs.ADCTRL1.bit.SEQ_OVRD = 0; // Enable Sequencer override feature
    AdcRegs.ADCCHSELSEQ1.all = 0x0; // Initialize all ADC channel selects to A0
    AdcRegs.ADCCHSELSEQ2.all = 0x0;
    AdcRegs.ADCCHSELSEQ3.all = 0x0;
    AdcRegs.ADCCHSELSEQ4.all = 0x0;
    AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 0x0; // convert and store in 8 results registers

    // Start SEQ1
    AdcRegs.ADCTRL2.all = 0x2000;

    for(;;)
    { // Take ADC data and log them in SampleTable array

    array_index = 0;
    for (i=0; i<(BUF_SIZE); i++)
    {
    while (AdcRegs.ADCST.bit.INT_SEQ1== 0){}

    AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;

    AdcBuf[array_index++]= ( (AdcRegs.ADCRESULT0)>>4);

    }

    }

    还有一个问题 如果设置多通道连续采样,采样频率是如何计算的,比如设置采样频率是12.5M 8通道连续采样,

    AdcRegs.ADCTRL1.bit.ACQ_PS = 0; // Sequential mode: Sample rate = 1/[(2+ACQ_PS)*ADC clock in ns]
    // = 1/(3*40ns) =8.3MHz (for 150 MHz SYSCLKOUT)
    // = 1/(3*80ns) =4.17MHz (for 100 MHz SYSCLKOUT)
    // If Simultaneous mode enabled: Sample rate = 1/[(3+ACQ_PS)*ADC clock in ns]
    AdcRegs.ADCTRL3.bit.ADCCLKPS = 0;
    AdcRegs.ADCTRL1.bit.SEQ_CASC = 1; // 1 Cascaded mode
    AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0;
    AdcRegs.ADCTRL1.bit.CONT_RUN = 1; // Setup continuous run

    AdcRegs.ADCTRL1.bit.SEQ_OVRD = 0; // Enable Sequencer override feature
    AdcRegs.ADCCHSELSEQ1.all = 0x0; // Initialize all ADC channel selects to A0
    AdcRegs.ADCCHSELSEQ2.all = 0x0;
    AdcRegs.ADCCHSELSEQ3.all = 0x0;
    AdcRegs.ADCCHSELSEQ4.all = 0x0;
    AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 0x7; // convert and store in 8 results registers

    // Start SEQ1
    AdcRegs.ADCTRL2.all = 0x2000;

    for(;;)
    { // Take ADC data and log them in SampleTable array

    array_index = 0;
    for (i=0; i<(BUF_SIZE); i++)
    {
    while (AdcRegs.ADCST.bit.INT_SEQ1== 0){}//在这里是12.5MHz/8的时间吗?

    AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;

    AdcBuf[array_index++]= ( (AdcRegs.ADCRESULT0)>>4);

    AdcBuf[array_index++]= ( (AdcRegs.ADCRESULT1)>>4);

    AdcBuf[array_index++]= ( (AdcRegs.ADCRESULT2)>>4);

    AdcBuf[array_index++]= ( (AdcRegs.ADCRESULT3)>>4);

    AdcBuf[array_index++]= ( (AdcRegs.ADCRESULT4)>>4);

    AdcBuf[array_index++]= ( (AdcRegs.ADCRESULT5)>>4);

    AdcBuf[array_index++]= ( (AdcRegs.ADCRESULT6)>>4);

    AdcBuf[array_index++]= ( (AdcRegs.ADCRESULT7)>>4);

    }

    }

  • 我觉得你还是没有完全理解ADC转换和CPU处理是两件不同的事件,现在把他们的时间或者频率混为一谈了。

    建议你再仔细理解一下我在这里的第二个回复,真正弄明白了我说的是什么,你这里的所有问题就都清楚了。

    ADC转换是ADC这个外设的事,它有触发采样的频率和转换速度,但是CPU能不能处理,那是你的程序设计和CPU能不能执行的问题。

    我们通常并不一定是每次ADC转换完成就必须去读取它的结果,因为这个时间一般比较短,这样的话CPU就什么都不用干了。

    你只需要硬件上配置ADC模块,让它按照一定的速度进行采样和转换,CPU根据时序进行数据处理就可以了。