• TMS320F28335利用ePWM改变ADC采样频率(双通道)示例代码


    2020-05-31 17:41:09

    TMS320F28335 想实现设定ADC采样频率,通过设置 ADC_CKPS 和 ADC_SHCLK 分频系数是可以在一定范围内改变ADC采样频率的,但是只调节分频系数时,ADC采样频率最低只能到十几KHz: 28335 ADC 对100Hz方波采样,于是问题变得复杂了一些。

    参考了有相同需求的帖子:28335的ADC采样频率如何设置? 、DSP28335中如何设置ADC采样的频率?

    得出结论:若想把ADC采样频率降低到一定水平(如1000Hz、2000Hz等),仅改变ADC分频系数是不够的,还需利用ePWM来生成ADC的启停信号,使其作为ADC的开关,释放启停信号来控制ADC,进而改变ADC的采样频率可调,而ePWM的频率就是ADC启停频率,

    于是我们现在关心ePWM的频率/周期设置:

    ePWM的寄存器主要有7个,我们这里重点关注:时基周期寄存器TBPRD和时基计数器模式:

    于是,决定Tpwm的变量有计算公式、TBPRD和TBCLK:

    (1).计算公式:不同计数模式的计算公式不同,从图中看出:

      在增减计数模式下,Tpwm = (TBPRD+1) x TBCLK ;

      在递增和递减计数模式下,Tpwm = 2 x TBPRD x TBCLK ;

    (2).TBCLK = SYSCLKOUT / ( (2*HSPCLKDIV) * (2^CLKDIV) );

    TBCLK由 SYSCLKOUT、HSPCLKDIV和CLKDIV决定,这里28335的SYSCLKOUT默认150MHz,查表后得知:代码中 CLKDIV = n ,公式中变为:CLKDIV = 2^n ;在程序中 HSPCLKDIV = n,公式中 HSPCLKDIV = 2n ;

    (3).TBPRD:按照公式(不同计数模式的Tpwm公式不同)计算得出数,手动填入,例如要把PWM的频率、(即ADC的采样频率)设置为2000Hz:

    1 // Set Period for EPWM1  
    2 // up-and-down count mode:
    3 // Tpwm = 2*(1/TBCLK)*TBPRD;
    4  
    5 // up-count mode or down-count mode:( use this mode here )
    6 // Tpwm = (1/TBCLK)*(1+TBPRD);    
    7     EPwm1Regs.TBPRD = (12500-1); // max = 65536
    8  // Setup  T(PWM1)=(1/TBCLK)*(1+TBPRD)=(1/25000000)*(1+12500-1)=0.0005s ,F(PWM1) = 1/T(PWM1) = 1/0.0005s = 2000Hz

    完整的可用ADC.c代码如下:

      1 #include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File
      2 #include "DSP2833x_Examples.h"   // DSP2833x Examples Include File
      3 #include "math.h"
      4 #include "DSP2833x_Project.h"
      5 #include "DSP2833x_EPwm.h"
      6 #include "DSP2833x_EPwm_defines.h"
      7 // lower sample rate to 2KHz using ePWM interrupt
      8 // as well as turn on 2 channels 
      9 
     10 // Determine when the shift to right justify the data takes place
     11 // Only one of these should be defined as 1.
     12 // The other two should be defined as 0.
     13 #define POST_SHIFT   0  // Shift results after the entire sample table is full
     14 #define INLINE_SHIFT 1  // Shift results as the data is taken from the results regsiter
     15 #define NO_SHIFT     0  // Do not shift the results
     16 
     17 #define BUF_SIZE   512  // Sample buffer size
     18 
     19     // Prototype statements for functions found within this file.
     20     interrupt void adc_isr(void);
     21 
     22     // Global variables used in this example:
     23     Uint16 LoopCount_1;
     24     Uint16 LoopCount_2;
     25     Uint16 ConversionCount;
     26 
     27     Uint16 SampleTable_1[BUF_SIZE]={0};
     28     Uint16 SampleTable_2[BUF_SIZE]={0};
     29 
     30 
     31     main()
     32     {
     33 
     34     // Initialize System Control:
     35     // PLL, WatchDog, enable Peripheral Clocks
     36     // This example function is found in the DSP2833x_SysCtrl.c file.
     37     InitSysCtrl();
     38 
     39     EALLOW;
     40     #if (CPU_FRQ_150MHZ) // Default - 150 MHz SYSCLKOUT
     41     #define ADC_MODCLK 0x3 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3) = 25.0 MHz
     42     #endif
     43     #if (CPU_FRQ_100MHZ)
     44     #define ADC_MODCLK 0x2 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 100/(2*2) = 25.0 MHz
     45     #endif
     46     EDIS;
     47     // Clear all interrupts and initialize PIE vector table:
     48     // Disable CPU interrupts
     49     DINT;
     50 
     51     // Initialize the PIE control registers to their default state.
     52     // The default state is all PIE interrupts disabled and flags are cleared.
     53     // This function is found in the DSP2833x_PieCtrl.c file.
     54     InitPieCtrl();
     55 
     56     EALLOW;
     57     SysCtrlRegs.HISPCP.all = ADC_MODCLK;                       // set ADC CLOCK ,HSPCLK = SYSCLKOUT/ADC_MODCLK
     58     EDIS;
     59 
     60     // Disable CPU interrupts and clear all CPU interrupt flags:
     61     IER = 0x0000;
     62     IFR = 0x0000;
     63 
     64     // Initialize the PIE vector table with pointers to the shell Interrupt
     65     // Service Routines (ISR).
     66     // This will populate the entire table, even if the interrupt
     67     // is not used in this example. This is useful for debug purposes.
     68     // The shell ISR routines are found in DSP2833x_DefaultIsr.c.
     69     // This function is found in DSP2833x_PieVect.c.
     70     InitPieVectTable();
     71 
     72     // Interrupts that are used in this example are re-mapped to
     73     // ISR functions found within this file.
     74     EALLOW; // This is needed to write to EALLOW protected register
     75     PieVectTable.ADCINT = &adc_isr;
     76     EDIS;                                                                                           // This is needed to disable write to EALLOW protected registers
     77 
     78     InitAdc();                                                                                     // For this example, init the ADC
     79 
     80     // Enable ADCINT in PIE
     81     PieCtrlRegs.PIEIER1.bit.INTx6 = 1;
     82     IER |= M_INT1;                                                                             // Enable CPU Interrupt 1
     83     EINT;                                                                                             // Enable Global interrupt INTM
     84     ERTM;                                                                                             // Enable Global realtime interrupt DBGM
     85 
     86     LoopCount_1 = 0;
     87     LoopCount_2 = 0;
     88     ConversionCount = 0;
     89 
     90     // Configure ADC
     91     ///////////////////////设置最大通道数:2/////////////////////////////
     92     AdcRegs.ADCMAXCONV.all = 0x0001;                                         // Setup 2 conv's on SEQ1
     93     AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0;                             // Setup ADCINA3 as 1st SEQ1 conv.
     94     AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x1;                             // Setup ADCINA2 as 2nd SEQ1 conv.
     95     //////////////////////////////////////////////////////////////////////    
     96     AdcRegs.ADCTRL2.bit.EPWM_SOCA_SEQ1 = 1;                            // Enable SOCA from ePWM to start SEQ1
     97     AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1;                             // Enable SEQ1 interrupt (every EOS)
     98 
     99     // Assumes ePWM1 clock is already enabled in InitSysCtrl();
    100     EPwm1Regs.ETSEL.bit.SOCAEN = 1;                                         // Enable SOC on A group
    101     EPwm1Regs.ETSEL.bit.SOCASEL = 4;                                         // Select SOC from from CPMA on upcount
    102     EPwm1Regs.ETPS.bit.SOCAPRD = 1;                                         // Generate pulse on 1st event
    103     EPwm1Regs.CMPA.half.CMPA = 0x0080;                                     // Set compare A value
    104     EPwm1Regs.TBCTL.bit.CTRMODE = 0;                                         // 0 -- count up and start
    105 
    106 ///////////////配置ePWM中断频率,即设置ADC采样频率////////////////    
    107 // High Speed Time-base Clock Prescale Bits,These bits determine part of the time-base clock prescale
    108 // SYSCLKOUT = 150MHz    
    109 // TBCLK = SYSCLKOUT / ( (2*HSPCLKDIV) * (2^CLKDIV) )=150MHz/(2*3*1)=25MHz      
    110    EPwm1Regs.TBCTL.bit.HSPCLKDIV =0x03; 
    111    EPwm1Regs.TBCTL.bit.CLKDIV = 0x00;
    112 
    113 // Set Period for EPWM1  
    114 // up-and-down count mode:
    115 // Tpwm = 2*(1/TBCLK)*TBPRD;
    116     
    117 // up-count mode or down-count mode:( use this mode here )
    118 // Tpwm = (1/TBCLK)*(1+TBPRD);    
    119    EPwm1Regs.TBPRD = (12500-1);                                            // max = 65536
    120 // Setup  T(PWM1)=(1/TBCLK)*(1+TBPRD)=(1/25000000)*(1+12500-1)=0.0005s ,F(PWM1) = 1/T(PWM1) = 1/0.0005s = 2000Hz
    121 //////////////////////////////////////////////////////////////////////
    122 
    123 // Wait for ADC interrupt
    124 while(1)
    125 {
    126     LoopCount_1++;
    127 }
    128 
    129 }
    130 
    131 
    132 interrupt void adc_isr(void)
    133 {
    134     LoopCount_2++;
    135     if(LoopCount_2 == 10000)
    136     {
    137     LoopCount_2 = 0;
    138     }
    139     SampleTable_1[ConversionCount] = AdcRegs.ADCRESULT0 >>4;
    140     SampleTable_2[ConversionCount] = AdcRegs.ADCRESULT1 >>4;
    141 
    142     // If BUF_SIZE(512) conversions have been logged, start over
    143     if(ConversionCount == BUF_SIZE)
    144     {
    145     ConversionCount = 0;
    146     }
    147     else ConversionCount++;
    148 
    149     // Reinitialize for next ADC sequence
    150     AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1;                                     // Reset SEQ1
    151     AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;                                 // Clear INT SEQ1 bit
    152     PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;                         // Acknowledge interrupt to PIE
    153 
    154 return;
    155 } 

    参考:

    DSP EPWM学习笔记1 - EPWM定时中断

    利用28335的epwm产生spwm波的总结

    F28335 使用EPWM控制ADC采样 能进ADC中断,但ADCRESULTx结果不对

    F28335 ADC多通道连续采样 代码+注释

  • 相关阅读:
    利用Unicorn和Idaemu辅助解决Geekpwn SecretCode
    2016-XCTF Final-Richman
    一道movfuscator混淆过的简单逆向
    airflow(二)集成EMR使用
    Airflow 调度基础
    集成学习与随机森林(二)Bagging与Pasting
    集成学习与随机森林(一)投票分类器
    决策树(二)决策树回归
    决策树(一)决策树分类
    SVM-支持向量机(三)SVM回归与原理
  • 原文地址:https://www.cnblogs.com/CCWangsj/p/13019365.html
Copyright © 2020-2023  润新知