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.

PROBLEM to change a GPIO's value for each peirod of T

HI,all.

I have a wired problem using C6713'timer and GPIO. I would appreciate for any help!

What I want to do is to change a GPIO's value every period of T . That is to say , at first, GPIO is set value 0 ,and after a certain period T ,the same GPIO  is set  1 . Then after another T , GPIO 0 again ,and so on.

 My idea : I use a timer to do this. when timer reaches the period T, it goes into the interrupt function , in which GPIO is set  0 or 1 alternatively .

here is the configuration:

1.   /*set gpio*/

 hGpio = GPIO_open(GPIO_DEV0,GPIO_OPEN_RESET); 

 GPIO_reset(hGpio);

GPIO_pinEnable(hGpio,GPIO_PIN12);       

GPIO_pinDirection(hGpio,GPIO_PIN12,GPIO_OUTPUT); 

2.   /*config the timer and enable the timer interrupt*/

hTimer1 = TIMER_open(TIMER_DEV1,TIMER_OPEN_RESET);

  TimerEventId = TIMER_getEventId(hTimer1);

   TIMER_configArgs(hTimer1,

    0x00000201, /* use internal clock*/

    T ,                   /* set period T  */

    0x00000000       );

IRQ_map(TimerEventId, 14);

IRQ_enable(TimerEventId);

3.while(1);  //wait the timer into the interrupt

4./*set the GPIO value in the interrupt function*/

interrupt void   

c_int14(void)   

{GPIO_pinWrite(hGpio,GPIO_PIN12,value);

value=!value;                             //value is either 0 or 1 }

PROBLEM:

I can see the GPIO is changed every T period. However, I also find that the GPIO is shaking . That is to say , the moment GPIO is set the opposite value is different for each round (period T).(about several ns).Is it caused by the uncerntain time DSP corresponds to the timer interrupt?I don’t know why.oscilloscope, 1.From the

2.I want the GPIO is set at the same time for each period exactly. I don’t hope that in this round  the GPIO is set at NT+t0,the GPIO is set at NT+ t1 .Is there another method to achieve it?

 

  • I believe you are experiencing the variation in interrupt latency due to the DSP executing code when an interrupt occurs. This is also referred to as interrupt jitter, and it can vary much more than a few nanoseconds depending on what the DSP is doing.

    If the DSP is executing some single-cycle instructions in a sequence when the timer interrupt occurs, then the interrupt process will be very fast and the latency will be at a minimum. If the DSP has just started a multi-cycle instruction such as a B branch when the timer interrupt occurs, then the interrupt will be held off until that Branch instruction completes. If the DSP is executing an optimized software-pipelined sequence with branches looping into the sequence, then the interrupt could be held off for 100's or 1000's of CPU cycles.

    The C Compiler has a switch -mi to set the interrupt latency threshold. But this will be measured in instruction cycles and can still be very long for what you are looking for.

    If you can manage to put the DSP into an IDLE instruction every time it is going to receive the timer interrupt (instead of the while  (1); loop), the latency should be minimized and consistent. This would not be practical for most applications, though.

    The timer has a timer output, TOUT0 or TOUT1, that can be driven directly by the timer. Please refer to the Timer Reference Guide for information on the use of the timer output, and refer to the C6713 datasheet for information on how to configure the TOUT0/AXR0[2] pin to be used as a timer output. You can still have the timer interrupt, and could use that to change the timer period or count if you want to have a varying signal on the output pin. But if you want a simple square wave, then the TOUTn pin will meet your needs without any further DSP interaction.

     

    If this answers your question, please click the  Verify Answer  button. If not, please provide additional information to help us understand the problem.

  • thanks for your suggestion, Randy. 

    I'll try to use TOUT .

    And I've thought another two  mehods to set GPIO:

    Method1:

    Timer's interrupt is disabled in this method .  Instead, after  gpio is set  as follows:

     TIMER_start(hTimer1);

    while(1)

    {  while (Timer_getCount(hTimer)<T ) ;   // the timer's PRD is more than T

          GPIO_pinWrite(hGpio,GPIO_PIN12,value);

          value=!value;

    }

    Method 2:

    In this method , i++ is used to config GPIO. That is to say , there is nothing to do with the Timer.THE CODE:

    while (1)

    {

    i=0;

    while (i< cnt )     // cnt is the number which represent T  approximately .

       i++;

     GPIO_pinWrite(hGpio,GPIO_PIN12,value);

          value=!value;

    }

    PROBLEM:

     Neither method is OK.

    For Method 1, I think while (Timer_getCount(hTimer)<T) is the problem.Is it correct ?

     And for mehod 2 ,although I will not  count using i++,  I 'm wondering why it doesn't work. would you please explain it? 

    thanks!

  • TOUT is the "right" solution for generating a regular and accurate square wave or periodic pulse. It will not use CPU bandwidth.

    Method 1, if you manage to catch the timer at the value T, could have as much or more jitter than your original plan. If you do not catch the timer at the value T, then you will miss one or more pulses whenever that occurs, and that would be disastrous. A better way to do Method 1 would be to save the value of the timer each time you read it, then compare the current value with the previous value. If the previous value is smaller than the current value, then the timer past through 0 and was reloaded to T. But the jitter is still large and you are using the CPU to generate a square wave which is not a good use of a fine DSP.

    Method 2 should work. What is it doing wrong? It should be low jitter, but not a good use of a fine DSP.

  • hi, Randy. Now I can use TOUT  to generate the square wave.

    How can I generate a  periodical wave  of which  duty cycle  is not 50% and can be configured by using timer and TOUT ?    

    I have to do this because the TOUT is used  as an enable pin and should follow some logic. 

    thanks!

  • xiaoer han said:
    How can I generate a  periodical wave  of which  duty cycle  is not 50% and can be configured by using timer and TOUT ?

    RandyP said:
    You can still have the timer interrupt, and could use that to change the timer period or count if you want to have a varying signal on the output pin.

    This statement was meant to describe what you want to do. At the end of each timer period, you will get an interrupt at the same time that the timer reloads the PRD registers into the TIM register. In the timer ISR, you may change the PRD register so that at the next interrupt a different value will be loaded from PRD to TIM. If you alternate between two values, T1 and T2, then you will accomplish your goal.

    Two things to be careful with in the ISR:

    1. You should read the CTL register to get the current value of the TOUT pin. This will help you stay in sync with the T1 and T2 values with respect to the state of TOUT.
    2. The value you write to PRD will not affect the current phase of the TOUT pulse sequence, but will affect the length of the next phase. If TOUT has just changed to 1 and the pulse width for TOUT=1 is T1, then you will now write T2 to PRD; this will set the length of the next phase when TOUT=0.

     

    If this answers your question, please click the  Verify Answer  button. If not, please provide additional information to help us understand the problem.

  • Sorry , Randy.I’m quite confused now.

    The TOUT pin can be configured as a general output pin (FUNC bit in CTL = 0 ) or timer output pin (FUNC=1) . What mode should I choose ?

    1.

    RandyP said:
    If TOUT has just changed to 1 and the pulse width for TOUT=1 is T1, then you will now write T2 to PRD;

     

    I guess you prefer to use TOUT as a general output .In this mode, I change its value using TIMER_setDatOut(hTimer,value) function and reconfigure the PRD to change the duty cycle in the timer ISR. However, it doesn’t work.The situation is just like what we have talked before—— to change GPIO value in the timer ISR.And this would cause interrupt jitter.  Is the TOUT pin directly driven by the timer when as a general output?

    2.If TOUT is configured as a timer output, TSTAT is driven on this pin. There are two basic pulse  modes , and it seems that neither can satisfy my need.

    thanks !

  • xiaoer han said:
    The TOUT pin can be configured as a general output pin (FUNC bit in CTL = 0 ) or timer output pin (FUNC=1) . What mode should I choose ?

    You want to use the timer output function. This way, whenever the timer expires to 0, the TOUT pin will toggle automatically without waiting for the ISR code to do it. This is what eliminates the interrupt jitter.

    RandyP said:
    If TOUT has just changed to 1 and the pulse width for TOUT=1 is T1, then you will now write T2 to PRD;

    Let me try to word this better. When TOUT is configured as a timer output, it will change each time the timer counts to 0. With no other CPU interaction, this will result in a square wave with period = PRD*2 since TOUT will TOUT at the end of each PRD count. However, you may also choose to have the timer generate a CPU interrupt each time the timer counts to 0. Since the timer automatically toggles TOUT and also reloads TIM with the value in PRD, if the new value of TOUT=1 then it will remain for the old count of PRD because the old value in PRD was loaded into TIM before the interrupt occurred. The ISR could write a new value into PRD, and this new value will be loaded into TIM the next time the timer counts to 0; the new PRD value will then be used as the timer duration for the *next* phase when TOUT=0.

    xiaoer han said:
    2.If TOUT is configured as a timer output, TSTAT is driven on this pin. There are two basic pulse  modes , and it seems that neither can satisfy my need.

    Hopefully, the explanation above helps you find a way to use TOUT as a timer output and adjust the PRD value to achieve your need.

  • hi,Randy

    RandyP said:
    When TOUT is configured as a timer output, it will change each time the timer counts to 0.


    After I configure TOUT as timer output pin and timer clock/pulse mode as CLOCK in CTL,  I can see  TOUT changes its value when timer counts to zero from the oscilloscope,

    RandyP said:
    However, you may also choose to have the timer generate a CPU interrupt each time the timer counts to 0.


    Well, when Timer's interrupt is enabled ,I find that when CTL is configured as above (TOUT and CLOCK mode), the timer does not generate a interrupt each time the timer counts to 0. For example, let's suppose timer's PRD  is set as T.  And then TOUT would output a square wave with period = T*2 while  the timer would go to the Interrupt function for the period of  T*2 . This can be  verified by changing a GPIO's value in timer's interrupt function and comparing the period of GPIO and TOUT.  ( GPIO = 2 * TOUT). I also find this  in spru582A.

    RandyP said:
    If TOUT has just changed to 1 and the pulse width for TOUT=1 is T1, then you will now write T2 to PRD;


    The PRD of timer is changed each time the timer goes into the interrupt . As timer doesn't go into the interrupt when counts downto 0 ,I get a periodical wave like this : T1(high) T1 (low) then T2(high) T2(low) and so on.

    Here is the timer configuration and ISR

    1.timer configuration

    static Uint32 TimerControl = TIMER_CTL_RMK(
       TIMER_CTL_INVINP_NO, 
       TIMER_CTL_CLKSRC_CPUOVR4,
       TIMER_CTL_CP_CLOCK, /* Clock/pulse mode(CP)
       TIMER_CTL_HLD_YES,
       TIMER_CTL_HLD_NO
       TIMER_CTL_GO_NO,
       TIMER_CTL_PWID_TWO,
       TIMER_CTL_DATOUT_1,
       TIMER_CTL_INVOUT_NO,
       TIMER_CTL_FUNC_TOUT /* Function of TOUT pin(FUNC).            
    );

        TIMER_configArgs(hTimer1,
        TimerControl,
        T1,   /* set period*/
        0x00000000  
       );

    2.timer interrupt function

    interrupt void   
    c_int14(void)   

    if (mux_flag==0)
    TIMER_setPeriod(hTimer1,T2);
    else
    TIMER_setPeriod(hTimer1,T1);
    mux_flag=!mux_flag;}

    PROBLEM:

    If the time doesn't  generate  a interrupt each time, is there any method to  achieve my need by using timer output ?

    Thank you very much

  • Sorry for my mistake on the timer interrupt. I see in Section 7 of SPRU582B that the frequency of the interrupt will be the same as the frequency of TSTAT.

    Here are the three methods that would work:

    DSP polling of TSTAT:

    I do not like suggesting this one because I do not like putting the DSP into continuous polling mode, but since you were considering it originally I will include it as an option. When the timer interrupt occurs, it will load the latest PRD (call it T1) into the TIM and begin counting down again. In the ISR, you can write a new PRD value (call it T2) that will be loaded when the timer reaches 0 next. Now, start a DSP polling loop reading TSTAT until it changes at the end of the current output phase. When TSTAT changes, write another PRD value (T1 again), and the waveform should be what you are looking for without jitter.

    Two timers:

    Rather than using the polling loop to wait for TSTAT to change, you could use the second timer in the C6713 to generate an interrupt just after when TSTAT changes in the middle of the square wave. You can do this by setting PRD1=0xFFFFFFFF. In the Timer0 ISR (the one generating the output), set TIM1=PRD0 (or TIM0) and set PRD0=T2. Timer1 will generate an interrupt when TIM1 reaches 0, and this will also be when you wanted to get an interrupt from Timer0 but cannot because of the timer design. In the Timer1 ISR, set PRD0=T1 and either let Timer1 continue running from the large value loaded from PRD1 or stop Timer1 and re-start it in the Timer0 ISR.

    Phase Adjustment (my preferred choice):

    In the Timer ISR, read the current value of TIM. Assuming that PRD=T2 and that you want the current phase to last for T1, subtract (T2-T1) from the value of TIM and also subtract a correction factor to account for the number of timer ticks that occur during this code execution. Write the new value to TIM, and this phase of the timer output will be adjusted.

    Because of the frequency difference between the DSP and the timer, there could be some phase jitter introduced by this Phase Adjustment method. I can think of 2 ways to try to avoid that jitter:

    1. Stop the timer, read TIM, subtract (T2-T1-correction), write TIM, start the timer. The correction factor may need to be a little larger, but this should work.
    2. Add some asm(" NOP"); instructions to tune the DSP code to be exactly a multiple of timer ticks from reading TIM to writing TIM. This will have to be tuned experimentally because the cycle count has to include the internal delays for the write to reach the TIM register.

    Let me know if this makes up for my mistake.

    RandyP

  • hi,Randy!

    According to the request , I choose method 1 (DSP polling of TSTAT), and it works!  I 've got  a very beatiful waveform  of  which duty cycle can be changed . I really appreciate for your warmhearted help.

    Still some  problems :

        1.  when emulation halt happens , the timer would continue counting .How to stop the timer when emulation halt and continue the timer when C6713 runs again?

           I have tried to set the SPND bit in CTL ,but it didn't work.

        2. Problem about measuring time with " i++"  

    RandyP said:
    Method 2 should work. What is it doing wrong? It should be low jitter, but not a good use of a fine DSP.

           It will cost dsp  a const  period of time to execute "i++" one time.   So I think  the total time would be a const when dsp executing  "while(i<n) i++" . Why "It should be low jitter"? Does it mean we can use i++ to measure time precisely ? For example , if  1ms delay is required , we just need to set a certain n .

    Thanks! 

  • xiaoer han said:
    I choose method 1 (DSP polling of TSTAT), and it works!

    Excellent! Glad to hear you have it working the way you want it to work.

    xiaoer han said:
    How to stop the timer when emulation halt and continue the timer when C6713 runs again?

    Some of our peripherals have FREE and SOFT bits in their control registers. These are used in combination to control the behavior during emulation halt, such as for the McBSP peripheral. These are not available for the timer.

    For the C6713, the timer will always continue to run during emulation halt, if it was running when the DSP was halted.

    The SPND bit is not available for the C62x/C67x DSPs, but was added for the C64x DSP family.

    xiaoer han said:
    It will cost dsp  a const  period of time to execute "i++" one time.   So I think  the total time would be a const when dsp executing  "while(i<n) i++" .

    This is all correct. This is why I think it should work, and I am curious why you did not get good results. It is possible that the compiler's optimizer will change a timing loop like this since it just sees a mathematical result that can be replaced with "i = n;". The use of the "volatile" keyword for the declaration of i can help avoid that.

    xiaoer han said:
    Why "It should be low jitter"? Does it mean we can use i++ to measure time precisely ? For example , if  1ms delay is required , we just need to set a certain n .

    Yes. If interrupts are disabled and nothing can interfere with the operation of the loop, then a DSP timing loop can be used for a very repeatable timer. Getting a precise number of clock cycles counted can be tricky. You might need to add some asm(" NOP"); instructions to add one cycle either inside the loop or after the loop. But if the delay for n=100 is N1 and the delay for n=101 is N2, then you can easily increment your delay in multiples of N2-N1.

  • RandyP said:
    Getting a precise number of clock cycles counted can be tricky. You might need to add some asm(" NOP"); instructions to add one cycle either inside the loop or after the loop.

    Let's suppose while(i<n) i++ stands for M instruction cycles(This can be achieved from the assemble program ). Now that M is a const ,why "getting a precise number of clock counted can be tricky"?

    thanks