This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Timer problem

Hi there!

I have some problems with CAPCOM timer. It was configured:

CPU clock - 40 MHz
prescaler - module clock / 8
Timer0 overflow (usec) - 100
Timer 0 reload register - 0xFE0C

On digital oscilloscope I can see ~9.615 kHz, not 10 kHz.

Can anyone explain this problem?

Some info:

_MCTC1 EQU 1
_RWDC1 EQU 0
_MTTC1 EQU 0

  • Hi

    How are you measuring this on an oscilloscope since T0 is not available on a pin as an output?

    If you just use the hardware and let's say CC8 as the output (P2.8) for your 10KHz signal you see this is rock solid on the oscilloscope.

    Here is the example…
    -Chris

    #include <xc167.h>
    
    void main (void) {
    
      /*  Configuration of CAPCOM1 Timer 0:
       *  CPU clock = 40 MHz
       *  timer 0 works in timer mode
       *  prescaler factor is 8
       *  200 usec per tick
      */
      CC1_T01CON = 0x0000u;
    
     /* Period is 50 usec, 20KHz */
      CC1_T0     = 0xFF06u;
      CC1_T0REL  = 0xFF06u;
    
      /*  Configuration of the used CAPCOM1 Channel 8:
       *  Compare mode 1: pin CC8IO (P2.8) toggles on each match
       *  CC8 allocated to CAPCOM1 timer 0
       *  CC8 toggles at half frequency of T0
       */
      CC1_CC8 = 0x10000u - ((0x10000u - 0xFF06u) / 2);
      CC1_M2  = 0x0005u;
    
      /* P2.8 is used for CAPCOM1 Output (CC8IO) */
      ALTSEL0P2 = 0x0100u;
      DP2       = 0x0100u;
    
      /* start timer zero */
      CC1_T01CON_T0R = 1;
    
        /* loop forever */
        for(;;) {
        }
    }
    

  • HI

    Yep, I use Capcom timer (now T7 instead T0) to generate 3-channel center-weight PWM with invert. Programm based on Keil example with MAC unit to calculate cos.

    I really can see only 9 kHz, not 10 kHz.

    Here it is:

    #include <regst10F269.h>
    #include <math.h>
    
    #define CLOCK  40000000L   // CPU configured for 40MHz clock
    #define SampleFreq  10000.0   // 8000 Hz Sample Frequency
    #define PI     3.141592654
    
    #define T0_RELOAD ((unsigned int )( 0 - ( CLOCK / SampleFreq ) / 8))
    
    // ----- Parameters and Variables for Sine Wave Generator -----
    #define OutFreq 50       // Output Frequency (Range  1Hz - 4000Hz)
    #define OutAmpl 0.95       // Output Amplitude (Range  0 - 0.99)
    
    #define T7INT     0x3D
    
    #define CC16INT    0x10
    #define CC1INT    0x11
    #define CC2INT    0x12
    
    int AA;
    int res, count, temp1, temp12, temp13;
    unsigned int temp, temp2, temp3;
    int res, t;
    
    struct tone
    {            // struct for Sine Wave Generator Signal
      int  y2;
      int  AA;
      int  y1;
      int  y0;
    };
    
    struct tone near Tone;
    struct tone near Tone2;
    struct tone near Tone3;
    
    // ----- DSP Functions -----
    
    
    __inline  void Generate_Sine (struct tone near *t)
    {
      __asm {
            PUSH R4
            PUSH R5
            PUSH R6
            PUSH R7
            PUSH R8
    
            MOV     R4, [t+]
        MOV     R5, [t+]
        MOV     R6, [t+]
            MOV     R7, [t]
    
        CoMUL   R4, R5              // Y2 * AA
            CoSHR   #1
            CoSHR   #1
            CoSHR   #1
            CoSHR   #1
            CoSHR   #1
            CoSHR   #1
            CoSHR   #1
            CoSHR   #1
            CoSHR   #1
            CoSHR   #1
            CoSHR   #1
            CoSHR   #1
            CoSHR   #1
            CoSHR   #1
    
            coSTORE R8, MAL          // R5 = Y2 * AA
    
            SUB     R8, R6
    
        MOV     [t], R6
        MOV     [-t],R4
        MOV     [-t],R5
        MOV     [-t],R8
    
            POP R8
            POP R7
            POP R6
            POP R5
            POP R4
      }
    }
    
    #pragma MAC
    
    static void timer0 (void) interrupt T7INT
    {
     static unsigned int CC16_image, CC24_image ; // Static register var trick
     static unsigned int CC19_image, CC27_image ; // Static register var trick
    
     static unsigned int CC17_image, CC25_image ; // Static register var trick
     static unsigned int CC20_image, CC28_image ; // Static register var trick
    
     static unsigned int CC18_image, CC26_image ; // Static register var trick
     static unsigned int CC21_image, CC29_image ; // Static register var trick
    
      T78CON &= ~0x0040;
    
      CC16 = CC16_image;CC19 = CC16_image;
      CC24 = CC24_image;CC27 = CC24_image;
    
      CC17 = CC17_image;CC20 = CC17_image;
      CC25 = CC25_image;CC28 = CC25_image;
    
      CC18 = CC18_image;CC21 = CC18_image;
      CC26 = CC26_image;CC29 = CC26_image;
    
      T78CON |= 0x0040;
    
      Generate_Sine (&Tone);
      Generate_Sine (&Tone2);
      Generate_Sine (&Tone3);
    
      temp1  =  ((unsigned int) Tone.y1 + 0x8000) / 298 + 15; //331 + 20;//315 +15;//298 + 15;//312 + 20;//285 + 10; //278 + 7;//
      temp12 = ((unsigned int) Tone2.y1 + 0x8000) / 298 + 15; //331 + 20;//315 +15;//298 + 15;
      temp13 = ((unsigned int) Tone3.y1 + 0x8000) / 298 + 15; //331 + 20;//315 +15;//298 + 15;
    
      CC16_image = 0xFE0C + temp1;
      CC24_image = 0xFFFF - temp1;
    
      CC17_image = 0xFE0C + temp12;
      CC25_image = 0xFFFF - temp12;
    
      CC18_image = 0xFE0C + temp13;
      CC26_image = 0xFFFF - temp13;
    
    }
    
    
    /******************************************************************************/
    /***************************      MAIN PROGRAM      ***************************/
    /******************************************************************************/
    
    
    unsigned int Signal;
    
    void main (void)// _task_ INIT
    {
      // RSTCON  = RSTCON & 0x40;    //Configure ResetOut
    
      // setup the timer 0 interrupt
      T7REL  =  T0_RELOAD/* + 23*/;        // 10 KHz reload value
      T7     = -(CLOCK / (8 * SampleFreq)); // 10 KHz reload value
      T7IC   = 0x44;
    
      T78CON = 0x40;             // start timer 0
    
      CCM4   = 0x5555;
      CCM5   = 0x55;
      CCM6   = 0x4444;
      CCM7   = 0x44;
    
      DP8   = 0xFF;
      P8    = 0x38;
    
      // Initialize Sine Generator
     AA = cos (  2 * PI * OutFreq  / SampleFreq ) * 32768  ;
    
     Tone.y0  = OutAmpl * ( cos ( 0 )) * 32768  ;
     Tone.y1  = OutAmpl * ( cos ( 0 + 2 * PI * OutFreq/SampleFreq )) * 32768  ;
     Tone.y2  = 2 * ( cos ( 2 * PI * OutFreq/SampleFreq)) * Tone.y1 - Tone.y0 ;
     Tone.AA  = AA;
    
     Tone2.y0  = OutAmpl * ( cos ( 2 * PI /3.0 ))* 32768;
     Tone2.y1  = OutAmpl * ( cos ( 2 * PI /3.0 + 2 * PI * OutFreq/SampleFreq ))* 32768  ;
     Tone2.y2  = 2 * ( cos ( 2 * PI * OutFreq/SampleFreq)) * Tone2.y1 - Tone2.y0 ;
     Tone2.AA  = AA;
    
     Tone3.y0  = OutAmpl * ( cos ( 4 * PI /3.0 ))* 32768 ;
     Tone3.y1  = OutAmpl * ( cos ( 4 * PI /3.0 + 2 * PI * OutFreq/SampleFreq ))* 32768  ;
     Tone3.y2  = 2 * ( cos ( 2 * PI * OutFreq/SampleFreq)) * Tone3.y1 - Tone3.y0 ;
     Tone3.AA  = AA;
    
     IEN  = 1;
    
     while (1);
    }
    

    Any ideas? Questions?

  • From what I can see you are stopping and starting T7 in your code without any compensation for the off time (again in the code).

  • Hi Chris!

    May be you right. But:

    It was done to prevent more than 2 comparations (mode 1 can do it) in one period of timer. I think it is reason of strange invert PWM signal. If you can - look at picture: rapidshare.com/.../sample.JPG.html

    My be someone know why it is happens and how to solve it?

  • Hi,

    1) I don't use ST devices only Infineon so maybe I can't help you very much.

    2) I can't download your picture since my time limit has expired for the free use.

    3) It appears to me you are using double compare mode and the 6 pins of P8 for your signals.

    4) CAPCOM2 doesn't have any shadow registers for the channels so you need to be very care full when updating the compare values.

    5) You have decided to update all the compare channels at the timer T7 interrupt and are trying to prevent any missing compare events by stopping T7. However you are not compensating for the time you shut down the timer nor are you really sure of the value of T7 when you stop it. So you still could have a problem here since you don't know what the real value is (most likely it is not zero due to interrupt latency and software execution time).

    6) My suggestion would to have a combination of interrupts, T7 and on the channel compares and dynamically choose when to update the new value as to prevent any glitches. So when the channel is not changing state near the T7 overflow use this interrupt to calculate the next compare value for these channels. If the changing state is near the T7 overflow then you need to update the compare value for the channel at the channel compare event interrupt.

  • Hi again!

    1) ST and infineon are quite similar but there are some mismatches.

    2)You can look at picture at another site:

    www.bestsharing.com/.../sample.JPG.html

    I am still needed in any advises about situation. May be someone have solved similar problem.

    3) Yes, you are right

    4,5) Yep. It is really reason of my problem with timer. If I do not stop timer - I can see 10 kHz PWM on hardware, but it looks like as at picture - with PWM signal invertion at some places.

    6) Thanks. I'll try it. Sounds like it can help. But I don't understand why 12 first "=" operations of interrupt can't be executed in proper minimum time when the changing state is near the T7 overflow.
    Are they really so time-consuming?

    CC16 = CC16_image;
    F2303482 MOV CC16,DPP2:0x0234

    With next string I made 15 value gap at both edges of timer period for 12 MOV commands.

    temp1 = ((unsigned int) Tone.y1 + 0x8000) / 298 + 15;

  • Hi,

    Where is the program execution from (internal or external)? In your first post you tell me that MCTC1 = 1 which means one wait state but is this where your program is executing from (CS1)?

    Given you are running at 40MHz this means you have a possible instruction cycle of 50nsec (without adding a wait state or if you are running from the external bus which has a path of 16-bit verses 32-bit internal).

    So if you make a rough calculation for the response time to get to the T7 interrupt before you begin processing anything. The minimum interrupt response time is 5 states (250nsec). This requires program execution from the internal code memory, no external operand read requests and setting the interrupt request flag during the last state of an instruction cycle. When the interrupt request flag is set during the first state of an instruction cycle, the minimum interrupt response time under these conditions is 6 state times (300nsec). This is just for the interrupt instruction to be fetched now it needs to make it through the pipeline to know it has to jump again to your interrupt service routine. Then you need to account for the preample of the interrupt frame. Which may look something like…

        89: static void timer0 (void) interrupt T7INT
    0002006A ECEF      PUSH     MSW
    0002006C EC2E      PUSH     MAL
    0002006E EC2F      PUSH     MAH
    00020070 C6ED0000  SCXT     MRW,#0x0000
    00020074 EC84      PUSH     IDX0
    00020076 C6030300  SCXT     DPP3,#0x0003
    0002007A C6871000  SCXT     MDC,#0x0010
    0002007E EC06      PUSH     MDH
    00020080 EC07      PUSH     MDL
    00020082 ECF4      PUSH     R4
    00020084 ECF5      PUSH     R5
    00020086 ECF6      PUSH     R6
    00020088 ECF7      PUSH     R7
    0002008A ECF8      PUSH     R8
    0002008C ECF9      PUSH     R9
       100:   T78CON &= ~0x0040;
    0002008E 6690BFFF  AND      T78CON,#0xFFBF
       102:   CC16 = CC16_image;
    00020092 F2302082  MOV      CC16,DPP2:0x0220
       103:         CC19 = CC16_image;
    00020096 F2332082  MOV      CC19,DPP2:0x0220
       104:   CC24 = CC24_image;
    

    Also notice that you have 16-bit and 32-bit opcodes and it takes an extra bus access to get the whole instruction from external memory (hence the advantage of the internal program memory bus which is 32-bits wide).

    Ok how many cycles do you have before you turn off the clock to T7?

    My suggestions to you would be…

    1) You cannot turn off T7 because as you stated you are making wave shaped signals based on a PWM value.
    2) Figure out when to update either in the timer interrupt or on the channel interrupt.
    3) Change "CoSHR #14" as the simulator doesn't like this but should work in the actual device.
    4) At least minimize the ISR something like this...

     while (1) {
     /* service here instead of in the T7 interrupt or make this a high
      * priority task in your system to know it will run as soon as the
      * T7 interrupt has finished
      */
      if(updatePWM == 1) {
        Generate_Sine (&Tone);
        Generate_Sine (&Tone2);
        Generate_Sine (&Tone3);
    
        temp1  = ((unsigned int) Tone.y1  + 0x8000) / 298 + 15;
        temp12 = ((unsigned int) Tone2.y1 + 0x8000) / 298 + 15;
        temp13 = ((unsigned int) Tone3.y1 + 0x8000) / 298 + 15;
    
        CC16_image = 0xFE0C + temp1;
        CC24_image = 0xFFFF - temp1;
        CC17_image = 0xFE0C + temp12;
        CC25_image = 0xFFFF - temp12;
        CC18_image = 0xFE0C + temp13;
        CC26_image = 0xFFFF - temp13;
        updatePWM = 0;
       }
     };
    


    This code for T7 ISR is greatly reduced…

       102: static void timer0 (void) interrupt T7INT {
       103:   T78CON &= ~0x0040;
    000204F2 6690BFFF  AND      T78CON,#0xFFBF
       104:   CC16 = CC16_image;
    000204F6 F2301682  MOV      CC16,DPP2:0x0216
       105:         CC19 = CC16_image;
    000204FA F2331682  MOV      CC19,DPP2:0x0216
       106:   CC24 = CC24_image;
    000204FE F2381A82  MOV      CC24,DPP2:0x021A
       107:         CC27 = CC24_image;
    00020502 F23B1A82  MOV      CC27,DPP2:0x021A
       108:   CC17 = CC17_image;
    00020506 F2311282  MOV      CC17,DPP2:0x0212
       109:         CC20 = CC17_image;
    0002050A F2341282  MOV      CC20,DPP2:0x0212
       110:   CC25 = CC25_image;
    0002050E F2391882  MOV      CC25,DPP2:0x0218
       111:         CC28 = CC25_image;
    00020512 F23C1882  MOV      CC28,DPP2:0x0218
       112:   CC18 = CC18_image;
    00020516 F2321082  MOV      CC18,DPP2:0x0210
       113:         CC21 = CC18_image;
    0002051A F2351082  MOV      CC21,DPP2:0x0210
       114:   CC26 = CC26_image;
    0002051E F23A1482  MOV      CC26,DPP2:0x0214
       115:         CC29 = CC26_image;
    00020522 F23D1482  MOV      CC29,DPP2:0x0214
       116:   T78CON |= 0x0040;
    00020526 76904000  OR       T78CON,#0x0040
       117:         updatePWM = 1;
    0002052A 0F00      BSET     0xFD00.0
    0002052C FB88      RETI
    

  • Hi Chris!

    I've done as you said. It really works! Even without stopping CAPCOM timer!

    You are most usefull man in this forum, thanks a lot.