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.

TM4C123GH6PGE: I need the edge_time example file.

Part Number: TM4C123GH6PGE

Hello 

The input edge timer sample source code is required.

There is no example file in the Peripherals folder. ( edge_count, oneshot_16bit, periodic_16bit, pwm)

I need the edge_time example file.

thanks

[Attach image of desired configuration ]

  • Extrapolating from the existing examples and the manuals, what have you tried?

    Robert
  • Hello Robert.

    i'm try to edge time and  An example that exists is an edge counter.

    The edge counter it's ok

    What's wrong with Edge Time?

    thanks.

    [Attach image files.]

    1. edge counter

    2. edge time


  • Hi Jame,
    Can you paste your code to look at?
  • Hello Charles.

    I want to get the example code. !!
    It's fast.

    Thanks.
  • Hi Jame,
    This post has an edge time example which will be helpful. e2e.ti.com/.../1676315
  • Hello Charles.

    I want sample code that does not have errors.

    Can I get the example source code?

    I saw the  " e2e.ti.com/.../1676315 "  address you said.

    I have a few questions.

    Why does Mr. Amit use Timer B (T0CCP1) together?

    thanks

    [ Attach image ]

  • Jame shin said:
    I want sample code that does not have errors.

    Mr. Shin - who here does "not" - seek just that?    Yet - most often - those, "Requesting such "error-free" code" invest the required time, effort, trial - to meet that stringent requirement!      This is not to say that you have not made much effort - yet as you've (not) yet reached your goal - does it not "fall squarely upon you" - to invest even more effort - in the pursuit of "code perfection?"     I am quite certain that vendor's Charles has made "best effort" - and thanks to Mr. Tsai - it is very likely that you are "converging" upon your objective.

    In that referenced post I was responsible for suggesting the simplification & speed-up which result (always) from "KISS."      In this specific case - I chose two Timer pins - one to interrupt upon rising edges - the other upon falling ones.        

    There are two important PWM measurement parameters: PWM frequency (or its inverse, period) and Duty Cycle.   Duty Cycle may be defined by the application - but most usually represents the, "Percent time "Active" scaled against the PWM period.    

    While your drawing is nice - it appears (to me) in error.     In terms of your diagram, Duty Cycle is that portion of the waveform which is at/around logic High and then "scaled" by the signal's period!     (i.e. Duty Cycle = Signal's time "high" / Signal's Period)    PWM Period is the time between back to back, like-polarity, signal edges.   (that designated by "T" in your drawing)    Your drawing neglects the scaling required between "Signal's time high & Signal's Period)    

    Should highest accuracy be your goal it may prove best to capture the "time delta" between "n" such "like-polarity" signal edges - which will reduce the effect of "timing jitter" upon your measurement.    (you would then divide that "total duration" by "n" - to determine the signal's period.)

    The beauty of such an MCU and closely coupled IDE system is the ability offered to perform such code development experiments.      The "feedback" you'll require is immediate - which enables you to move systematically toward YOUR (more proper) GOAL of, "Jame's created code" - which (of course) does NOT have errors!"

    So James - time for you to develop YOUR "error-free" code - and provide it here for your "helpers."

  • Jame shin said:
    I want to get the example code.

    Jame shin said:
    I want sample code that does not have errors.

    Seriously???

    Does TI ever promised/advertised you they will sell microcontrollers and also make the program for your application?

    Being critical here won't help, but if that's ALL what it takes to develop products, the lady serving coffee downstairs is a serious competitor to you, Jame shin.

    And if you don't understand the reason beyond the inspiring solution of using two timers for measuring one PWM signal, then I suggest you study it some more... or the lady serving coffee might as well get the position...

    Bruno

  • cb,
    I second your request!
    Hopefully complemented by the code with FIR filters to eliminate measurement errors or existing sensor/signal oscillations.
    Bruno
  • Dear Mr. Cb1_Mobile

    Thank you for your discipline.
    I am a beginner and I am learning.
    I agonize a lot of time. Then ask E2E for help.
    It is not my concern that the timer value changes with the jitter you are talking about.
    but I have invested time and effort into analysis. So it's a block diagram with one question.
    I was just asking the edge time implementation question.
    because There is no example provided by Ti.
    So we refer to the edge count and ask if the procedural order is correct.
    I do not know what purpose you are talking about. discipline or help
    My question is out of focus.
    I do not know what the technical content you are talking about is.

    thanks
  • Hello Mr. Bruno

    You don't have to be sarcastic with me

    Why not tell me why you need to measure with two timers?

    So what is the correct value for each of the two timers ?

    thanks
  • I am not being sarcastic, Jame - I'm being sincere. Maybe in the near future, "harsh" comments like this will challenge you and make you a better professional. High class professionals on any activity don't become such without a lot of push, sweat, dedication. Again, if it was that easy to ask for "a working piece of software for my application", even I would probably need a better job! It is constructive criticism, don't understand it the other way.

    Do you want a few more minutes to try to figure out why the use of two timers? Then stop reading, close this message.

    ...
    ... (spoiler alert)
    ...

    When you configure a timer on capture mode, you need to choose the transition border that will trigger the interrupt: either rising, falling, or both. Once inside the ISR, there is no way to tell which was the direction that triggered it if you had chosen "both". Hence, you can measure 3 consecutive transitions, but you can't tell the difference of a 30% cycle from a 70% cycle. If you divert the signal to two timers, and configure one for rising transition, and the other for falling transition, then you can tell the difference.
    There is a workaround: if your signal is not tooooo fast (there are discussions elsewhere here as to the practical limits), you can use only one timer, set the interrupt to either falling/rising, and once in the ISR, read the pin status to tell if it is high or low. A second, faster workaround - but more complex - is to set a DMA transfer of both the GPIO and the TIMER counter when the transition occurs, so that you record "the whole picture" on transition instant, and evaluate it later on.

    Don't get too desperate - this whole comprehension of all the timer's nuances will not come in a week's study. It naturally takes time to mature.

    Bruno
  • Hi Jame,
    Your PWM period is 1Khz according to your diagram. But what will be your duty cycle?

    Let's do some calculation. 1Khz means 1ms period. if you need to capture a 1% duty cycle then it means the duty cycle width to capture is about 10us. Let's say you only use one timer and enable both edges to generate interrupt for capture. If you are running at 80MHz then the CPU clock period is 12.5ns. The 1% duty cycle is then equal to 10us/12.5ns=800 CPU cycles. At the rise edge an interrupt is generated. In the ISR you will record the timestamp put into a temp variable. At the next fall edge you will generate interrupt again. In the ISR you will again record the timestamp. The difference between these two timestamps is your duty cycle length in terms of # of cycles.

    If you don't have a lot of code in your ISR then there should be no issue to serve two interrupts within 800 cycles.

    But, what happen if your application requires your to capture a duty cycle that is 0.01% of a period? 0.01% means you need to capture a duty cycle width that is 100ns. This translates to 8 CPU cycles. This will be kind of too short for the CPU to service two interrupts (one for rise edge and another for fall edge). The reason is that the first time the CPU sees a rise edge interrupt it takes some time to enter the ISR. By the time the CPU is in the ISR trying to read the timestamp the timer capture register has already been overwritten with the timestamp for the falling edge. You cannot measure your 0.01% duty cycle if this is your application using one timer.

    If you have two timers then you can capture the timestamp for the rise edge using let's say timerA. After the rise edge interrupt is generated the timestamp is captured. When the fall edge interrupt is generated, even though it comes very fast in about 8 CPU cycles, the timestamp for the fall edge is captured into the timerB which does not overwrite the capture register in timerA. This is the reason that two timers are used.
  • Hi Charles,

    It should be noted as well that the "Two Timer" method (which "sprang" from my far earlier suggestion of "KISS") proves far simpler & faster to program & implement - and that (always) should be a strong consideration.    The time for "absolute optimization" is NOT during, "First Pass Code Development" - instead should only be attempted when it has been "proven" that any such "optimization" answers a "real need" or yields a measurable "saving."    (thus justifies the required extra time/effort/cost.)

    I wrote - rather clearly for Jame - that one timer captured "Rising Edge" - the second "Falling Edge" - his "miss of that" may indicate that "several slower readings" of  detailed, "helper response" will prove helpful.

    Again - the "demand" for "error-free" code is highly unusual - and is outside the purpose & intent of this (and to my mind) "ANY" forum!  Each/every forum user - in pursuit of such - must employ (their own) time/effort/diligence - in that pursuit!        It is NOT something to be "commanded" - and/or "ordered up" - which appears to be poster's (improper and/or misunderstood) desire...

  • Hello Charles.

    Thanks for the detailed explanation.

    I analyzed it with what you said.

    I have figured out what I understand.

    Is it right ?

    thanks.

    [Attached Images]

  • Charles.

    Go back to the first question

    I have two worries.

    1.  Can not read the clock of the set time module?

    2. The order of the Printf statements depends on the position of the interrupt routine.

        How do I change it?

    Thanks.

    [Attached Images]


    [ example Source Code]

     

     - It is modified from the Ti example source.

    //*****************************************************************************
    //
    // edge_count.c - Timer edge count mode example.
    //
    // Copyright (c) 2013-2015 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    // 
    //   Redistribution and use in source and binary forms, with or without
    //   modification, are permitted provided that the following conditions
    //   are met:
    // 
    //   Redistributions of source code must retain the above copyright
    //   notice, this list of conditions and the following disclaimer.
    // 
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the
    //   documentation and/or other materials provided with the  
    //   distribution.
    // 
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    // 
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    // 
    // This is part of revision 2.1.2.111 of the Tiva Firmware Development Package.
    //
    //*****************************************************************************
    
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "driverlib/debug.h"
    #include "driverlib/fpu.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/timer.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "grlib/grlib.h"
    #include "drivers/cfal96x64x16.h"
    #include "utils/ustdlib.h"
    #include "driverlib/uart.h"
    #include "utils/uartstdio.h"
    
      // Flags that contain the current value of the interrupt indicator as displayed  on the CSTN display.
    
        uint32_t g_ui32Flags;
    
    
       // An interrupt counter indicating how often the timer down counter reached
    
        volatile uint32_t g_ui32IntCount;
    
    
      // The graphics context used to draw on the display.
        tContext g_sContext;
    
    
      // A buffer used for string formatting.
    
        #define PRINT_BUFF_SIZE 8
        char g_pcPrintBuff[PRINT_BUFF_SIZE];
    
    
    void
    InitConsole(void)
    {
      // Enable GPIO port A which is used for UART0 pins.
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    		
      // Enable UART0 so that we can configure the clock.
        SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
    
        GPIOPinConfigure(GPIO_PA0_U0RX);
        GPIOPinConfigure(GPIO_PA1_U0TX);
    
      // Use the internal 16MHz oscillator as the UART clock source.
        UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    
        
      // Select the alternate (UART) function for these pins.
        GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
      // Initialize the UART for console I/O.
        UARTStdioConfig(0, 115200, 16000000);
    }
    
    
    void
    ProcessInterrupt(void)
    {
        //
        // Update our interrupt counter.
        //
        g_ui32IntCount++;
    
        //
        // Toggle the interrupt flag telling the main loop to update the display.
        //
        //HWREGBITW(&g_ui32Flags, 0) ^= 1;
        HWREGBITW(&g_ui32Flags, 1) ^= 1;
    }
    
    
    // Initialize the display.  This function is specific to the  EK-LM4F232 board
    void
    InitDisplay(void)
    {
        tRectangle sRect;
    
        // Initialize the display driver.
        CFAL96x64x16Init();
    
        // Initialize the graphics context and find the middle X coordinate.
        GrContextInit(&g_sContext, &g_sCFAL96x64x16);
    
        // Fill the top part of the screen with blue to create the banner.
        sRect.i16XMin = 0;
        sRect.i16YMin = 0;
        sRect.i16XMax = GrContextDpyWidthGet(&g_sContext) - 1;
        sRect.i16YMax = 9;
        GrContextForegroundSet(&g_sContext, ClrDarkBlue);
        GrRectFill(&g_sContext, &sRect);
    
        // Change foreground for white text.
        GrContextForegroundSet(&g_sContext, ClrWhite);
    
        // Put the application name in the middle of the banner.
        GrContextFontSet(&g_sContext, g_psFontFixed6x8);
        GrStringDrawCentered(&g_sContext, "edge-count", -1,
                             GrContextDpyWidthGet(&g_sContext) / 2, 4, 0);
    
        // Initialize timer status display.
        GrContextFontSet(&g_sContext, g_psFontFixed6x8);
        GrStringDraw(&g_sContext, "Countdown:", -1, 8, 26, 0);
        GrStringDraw(&g_sContext, "Interrupts:", -1, 8, 36, 0);
    }
    
    
    void
    MainLoopRun(void)
    {
        uint32_t ui32Count, ui32LastCount;
    
        // Set up for the main loop.
        ui32LastCount = 1;
    
        // Loop forever while the timer runs.
        while(1)
        {
            // Get the current timer count.
            ui32Count = ROM_TimerValueGet(TIMER4_BASE, TIMER_A);
    
    		
            if(ui32Count != ui32LastCount)
            {
                // update the display.
                usnprintf(g_pcPrintBuff, PRINT_BUFF_SIZE, "%d ", ui32Count);
                GrStringDraw(&g_sContext, g_pcPrintBuff, -1, 80, 26, true);
    
                // Remember the new count value.
                ui32LastCount = ui32Count;
    						
    	     UARTprintf("Button CNT = %d \n", ui32Count);
    
            }
    
            // Has there been an interrupt since last we checked?
            if(HWREGBITW(&g_ui32Flags, 1))
            {
                // Clear the bit.
                HWREGBITW(&g_ui32Flags, 1) = 0;
    
                // Update the interrupt count.
                usnprintf(g_pcPrintBuff, PRINT_BUFF_SIZE, "%d ", g_ui32IntCount);
                GrStringDraw(&g_sContext, g_pcPrintBuff, -1, 80, 36, true);
    			
    	          UARTprintf("INT-Count  = %d \n", g_ui32IntCount);
    	          // UARTprintf("g_ui32Flags  = %x \n", &g_ui32Flags);		 
            }
    
        }
    }
    
    
    
    // The interrupt handler for timer 4.  
    
    void
    Timer4IntHandler(void)
    {
        // Clear the timer interrupt.
        ROM_TimerIntClear(TIMER4_BASE, TIMER_CAPA_MATCH);
    
        ProcessInterrupt();
    
    
        // The timer is automatically stopped when it reaches the match value so re-enable it here.
        ROM_TimerEnable(TIMER4_BASE, TIMER_A);
    }
    
    
    int
    main(void)
    {
    
        //ROM_FPULazyStackingEnable();
    
        //ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
        //                   SYSCTL_XTAL_16MHZ);
    
        ROM_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
                            SYSCTL_XTAL_16MHZ);
    
      // Timer Moudle(Timer A & Timer B) Clock Source Set
    	// TimerClockSourceSet(TIMER4_BASE, TIMER_CLOCK_SYSTEM);
    
      // Initialize the display on the board. 
        InitDisplay();
    		
      // UART Func Call
    	  InitConsole();
    		
    	UARTprintf("\nSYSCLK  = %d Hz\n", SysCtlClockGet());
    	
      // Enable Timer4 & GPIOM
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER4);
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOM);
    
      // Configure PM0 as the CCP0(Timer A) pin for timer 4.
        	ROM_GPIOPinTypeTimer(GPIO_PORTM_BASE, GPIO_PIN_0);
        	GPIOPinConfigure(GPIO_PM0_T4CCP0);
    
      // Set the pin to use the internal pull-up.
        MAP_GPIOPadConfigSet(GPIO_PORTM_BASE, GPIO_PIN_0,
                        GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
    
      // Enable processor interrupts.
       	ROM_IntMasterEnable();
    
      // Configure the timers in edge count mode.
      //ROM_TimerConfigure(TIMER4_BASE, (TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_COUNT));
    	  ROM_TimerConfigure(TIMER4_BASE, (TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_COUNT_UP));
        ROM_TimerControlEvent(TIMER4_BASE, TIMER_A, TIMER_EVENT_POS_EDGE);
        ROM_TimerLoadSet(TIMER4_BASE, TIMER_A,15);
    	//ROM_TimerLoadSet(TIMER4_BASE, TIMER_A, 9);
        ROM_TimerMatchSet(TIMER4_BASE, TIMER_A,15);
    	//ROM_TimerMatchSet(TIMER4_BASE, TIMER_A, 0);
    
      // Setup the interrupt for the edge capture timer.  Note that we
      // use the capture match interrupt and NOT the timeout interrupt!
        ROM_IntEnable(INT_TIMER4A);
        ROM_TimerIntEnable(TIMER4_BASE, TIMER_CAPA_MATCH);
    		
    	// Timer Moudle(Timer A & Timer B) Clock Source Set
    		TimerClockSourceSet(TIMER4_BASE, TIMER_CLOCK_SYSTEM);  // TIMER_CLOCK_PIOSC or  TIMER_CLOCK_SYSTEM
    
      // Enable the timer.
        ROM_TimerEnable(TIMER4_BASE, TIMER_A);
    		
    	//  timer module source clock
    	  UARTprintf("TimerClk  = %d Hz \n", TimerClockSourceGet(TIMER4_BASE));
    
    
      // At this point, the timer will count up every time a negative  edge is detected on the relevant pin .
        MainLoopRun();
    }
    

     

  • Hello Jame,

    You did a great work with these diagrams and on your understanding. Well done! A few more notes to help you achieve your goal:

    1- If it was not clearly said, your timers will need to run synchronized. Here's a thread about it as guidance:

    e2e.ti.com/.../587248

    2- You don't have to permanently monitor the timer value in the main loop, just let the interrupts do it for you. Here's an idea (this is untested, just wrote it as an example...)

    void Timer1A_ISR(void)
    {
        uint32_t ui32Status;
        ui32Status = ROM_TimerIntStatus(TIMER1_BASE, true);
        TimerIntClear(TIMER1_BASE,ui32Status);
        if (ui32Status & TIMER_CAPA_EVENT)
        {
    	  pwmRisingCountLast = TimerValueGet(TIMER1_BASE, TIMER_A);
    	  flagNewCountAvailable = true;
        }
    }
    

    3- Same applies, of course, for the other timer

    4- Inside your main loop, you can make new calculations only when needed. Something like this:

    while(1)
    {
        if (flagNewCountAvailable)
        {
    	  MakeCalculations();
    	  flagNewCountAvailable = false;
        }
    }

    5- For the calculations, you need to mind that the 16-bit timers are actually smaller then the expected period (unless you want to wire the signals into two 32-bit timers, which is a good idea)

    void MakeCalculations(void)
    {
        /*
         * period = the clock difference pwmRisingCountLast - pwmRisingCountPrevious,
         * BUT accounting for rollover and timer width
         */
        
        /*
         * dutywidth = the clock difference pwmFallingCountLast - pwmRisingCountPrevious,
         * also minding rollover and widths 
         */
        
        duty = dutywidth / period;
        pwmRisingCountPrevious = pwmRisingCountLast;
    }

    6- If you are seeing your values on a console via UART, or on a screen, there is not much point in seeing then 1000 times per second. So you may want to determine a more convenient moment to send the current result. Also, you may want to use some filtering or averaging on your readings, depending what your sensor is.

    By the way, what editing program do you use to create those schematics?

    Regards

    Bruno

  • Hi Jame,
    Very nicely drawn diagram. Your understanding is correct on the behavior and how to handle such a situation using the robust two timer solution.
  • Bruno Saraiva said:
    there is not much point in seeing then 1000 times per second

    Nor is - (human or animal) vision - able to process visual data arriving @ 1mS intervals.     (most can "barely" detect the "Olympic Timer Clocks" - usually updating at 100mS intervals...)

    Indeed poster produces "best ever" diagrams - bit more "organized & focused effort" will see the (desired) SELF-CREATED, Error Free Example Code!

  • Hi,
    Yes it depends where the code in the while loop when the interrupt happens. The polling operation in your while loop and the interrupt is a bit asynchronous to each other. For example, while you are sending the value "14" to the terminal an interrupt is detected and print out the INT-Count=1 soon after.
  • Hi Charles,

    From the "ongoing, broken-record department" might our poster clearly benefit from the: "Simplification, Ease, & heightened Focus" - all achieved via his adoption of, "KISS?"

    The attempt to "integrate" so many of the "non-vital" program facets/sections plagues the poster - and overly complicates "your" time/effort in resolving. And - it should be noted - the bulk of poster issue arrives from, "Outside the TM4C's behavior" - instead is encouraged by his "Introduction of Needless, Extra Complexity!" And such "forces you" from your central "TM4C focus" - into basic, "Problem Solving."

    And while banned here - "KISS" (as some would note) is a strong actor in eliminating such complexity - and in guiding multiple posters to, "Faster, Easier, & (even) Enhanced" Solutions - all achieved via the (proper) reduction of variables & "issues in play!"
  • Hi cb1,
    Thank you for your suggestion to the poster and I agree with you to first keep things simple to start with and build up the working pieces. I will suggest to first cut out the code related to the display function.
  • Hello Bruno.

    I feel good about your praise.
    The editor program is MS-PowerPoint.
    I have one question.
    Why can not I read the timer clock?
    - UARTprintf("TimerClk = %d Hz \n", TimerClockSourceGet(TIMER4_BASE));

    thanks
  • Jame,
    What are you trying to read?
    TimerClockSourceGet() will return either one of two defined macros: TIMER_CLOCK_SYSTEM or TIMER_CLOCK_PIOSC, not a "numeric value". That's explained on 29.2.2.3 of Tivaware Driverlib User Guide.
    Are you looking for the frequency value of the clock driving the timer (as in 80000000)?
    - you could use that TimerClockSourceGet() first to confirm that the timer is being driven by the System Clock
    - if so, read the system clock - in your case you are using TM4C123, so that can be done via SysCtlClockGet()
    - Otherwise, then the value is PIOSC, which is a less precise 16000000 Hz clock.
    But you don't usually need to read that frequency during runtime calculations - you just better make sure you configured the timer with the clock that YOU want, and save that value in some variable.
    Bruno
  • Bruno

    In the above edge counter source, the timer clock is set to system clock.

    TimerClockSourceSet(TIMER4_BASE, TIMER_CLOCK_SYSTEM); // TIMER_CLOCK_PIOSC or TIMER_CLOCK_SYSTEM

    .
    .
    UARTprintf("TimerClk = %d Hz \n", TimerClockSourceGet(TIMER4_BASE))

    So I want to read the timer clock.

    thanks
  • Jame,
    I believe that is exactly what I just replied and explained to you. Please read my previous message again and let me know.
    Bruno
  • Bruno

    I did not perfect understand the previous content.

    Like the formula, is the timer value 0 ?

    I do not know this.

    thanks

    [ Attach image]

  • Jame,
    Running at 80MHz, each systemClock takes 12.5ns. The period evaluation is pure math - you have to discover how many clocks passed between events and convert that to an amount of time.
    Bruno
  • *** LIKE ***
    (note: single, well debounced, Like Switch implemented here...) Very good explanation - poster's (obsession) w/"drawings" may cloud his basic thought process...

    Simple experimentation with the Timer should clarify - poster's introduction of "So much extra" diverts him from his "central task."     (think "surgery" - the area in question is "clear" - ALL else is "draped" - thus focus is "forced upon the issue (tissue) at hand" - not the extraneous!)      

    Of course - this proves (just another) example of KISS - most always "kicked to the curb" here...   (at the cost of needless "pain/suffering.")

  • Hi Jame Shin,

    Jame shin said:

    UARTprintf("TimerClk = %d Hz \n", TimerClockSourceGet(TIMER4_BASE))

    Bruno is correct that syntax only returns the source clock used for GPTM module not the value of counter registers relative to source clock time. 

    So we must read the GPTM register count after an interrupt to get the value for edge time examination. The datasheet explains each GPTM configuration mode in great detail yet document GPTM errata may effect method or count direction depending on usage. Be sure to check errata document for GPTM modes effected.

     Below we calculate the edge count after the GPTM match count interrupt fires a one shot timer that fires a tick handler in 1 second intervals.. Similar calculation of specific syntax point inside a handler after entering an interrupt can be done with edge timer registers. We really don't care about rising/falling signal edge times into NVIC interrupt controller only that software can concatenate such time via register values of hardware. Don't worry how fast the edge time NVIC will react to your 1Khz PWM input (not so relative) rather the counters ability to capture and record said time relative to registers values and match interrupt times are.

    /* Get GPTMTBV free running count value. */
    ui32TBVEdgeCount = HWREG(TIMER0_BASE + TIMER_O_TBV);
    
    /* Get GPTMTBILR current matching edge counts */
    ui32TBILREdgeCount = HWREG(TIMER0_BASE + TIMER_O_TBILR);
    
    /* Determine the total number of counted edges up to ISR */
    ui32EdgeCount = ui32TBILREdgeCount - ui32TBVEdgeCount;

  • Hi Jame,

    Sorry for the late reply. What Bruno meant to say was that the API simply returns the register value which indicates what the clock source is, not the frequency of the clock source. Please take a look at the API function where the timer control register is read to return the API function.

    uint32_t
    TimerClockSourceGet(uint32_t ui32Base)
    {
        //
        // Check the arguments.
        //
        ASSERT(_TimerBaseValid(ui32Base));
    
        //
        // Return the timer clock source.
        //
        return(HWREG(ui32Base + TIMER_O_CC));
    

  • hello Bruno.

    It has changed to the amount of time Mr.Brono said.
    To apply the source code to multiply the total number of counters by 12.5 ns
    (calculate)
    x1 time = 12.5ns x 8 cycles (count detection) = 0.1 us
    x2 time = 12.5ns x 79992 cycles (count dection) = 999.9 us

    But there is something I want to ask.
    What procedural method does the x1 timer value detect?

    Because of the very short 0.01% duty ratio, ISR jump processing problems
    I understand the reason for separating the timer.

    2 Timers are synchronized, starting with different edge interrupts and counting to the next interrupt.
    How do you know the counter value of X1?

    thanks.
  • Hello BP101.

    Mr.Burono explained that the return value of the TimerClockSourceGet() function is not a numeric value.

    Thank you for your attention and help.

    Mr. Charles informed me of his previous post on the Edge Time Implementation Study.

    " Don't worry how fast the edge time NVIC will react to your 1Khz PWM input"

    I do not know what you're talking about.

    They are concerned about the problem and looking for a solution.

    I'm just studying the content.

    I have one question.

    In the attached image, please explain why the timer clock is at least 4 times the input signal ?

    thanks.

    [attached image]

  • Hello  charles.

    Please let me know 4 questions in the attached image.

    thanks

    [ attached image]

  • Jame shin said:
    x2 time = 12.5ns x 79992 cycles (count dection) = 999.9 us

    Not here - nor now!     Might "scientific notation" & slight "rounding" assist?

    [edit]  Whoops - swear I saw that cycle number as 7992 - see (now) that it is not.    To the list of "sci notation" & "rounding" - appears "eyesight" (or wakefulness) must be added...

    Thus:  (1.25 * 10 ^ -8)  *  (8 * 10 ^ 4) = 10 ^ -4 = 0.001000 which is 1000 µS!     Such (back of the envelope) "Quick Calcs" usually avoid "order of magnitude" errors (but not numeric mis-reads.)

  • Hi Jame,

    Jame shin said:
    In the attached image, please explain why the timer clock is at least 4 times the input signal ?

    The GPTM source clock does not have to run a SYSCLK speed and can depending on the application use PIOSC 16Mhz internal precision clock source gives timer a 62.5ns tick.

    Sorry for confusing your edge time example software request, it seemed you were requesting to calculate the rising edge time and not specifically concatenating the time between two different edges which has nothing to do with rising edge time. To keep it simple try to calculate edge times for CCP inputs as a total number of GPTM ticks relative to SYCLK or PIOSC using the formula 1/F. Not sure why exactly the need to use two CCP inputs interrupts when a 24 bit edge timer should easily determine the frequency of a single input signal relative to GPTM timer ticks. 

    There is a formula in datasheet use to determine GPTM source clock rate relative to CCP input frequency GPTM might be expected to measure.  

    BTW 1Khz = 1ms does it not.

  • Hi Jame,
    A1: I thought you already had your answer in the diagram. x1=0.1us or 100ns. x2=(1ms or 1000us)-0.1us=999.9us
    A2: You can do with 16bit+8bit. 2^24=1677721*12.5~=210ms which is more than enough for your application.
    A3/A4. I don't understand your question about setting the source code. Are you looking for the APIs? Please refer to TimerPrescaleSet and TimerLoadSet if you want to use 24bit timer.
  • Hello Charles.

    I have not correctly communicated the key questions. Sorry

    A1 Answer the question again ..

    In the block diagram, the time values of x1 and x2 are displayed.

    I first asked the edge time question to refer to the post address e2e.ti.com/.../1676315. .

    In the course of the question, x1 and x2 are preset values to account for the worst case.

    If the time value is detected with a very fast time (0.1us) of duty ratio of 0.01% for only one timer,
    there is a problem that the time stamp is overwritten.

    So the problem is that we do not know the time value of x1.

    As a solution, I explained that one timer is not used as a timer and two timers are used.

    Timer A also sets an interrupt on every rising edge.

    And Timer B sets the interrupt occurrence every Falling.

    Therefore, the MCU can not know the x1 and x2 time values

    I think I will detect the time value in procedural sequence.

    The timer starts when the first interrupt occurs and ends when the next interrupt occurs

    How can I detect the time value of X1 because Timer A is interrupted only when rising and Timer B is interrupted only when it is falling?

    thanks.
  • Hi Jame,
    Sorry, I'm not sure I understood your question. You will synchronize both timer A and timer B so they will start counting at the same time. In the interrupt for timer A (when a rise edge is detected) you read the captured timestamp value from timer A. In the interrupt for timer B (when a fall edge is detected) you read the capture timestamp value again from timerB . The difference between the two is your x1.
  • Hello Charles.

    Thank you for your reply.

    I did not understand.

    I will ask you more details.

    thanks

    [ attached image]

  • In defense of vendor's Charles - we do not know how he could "write any more clearly!"

    Is it possible that your drawing contains too much - thus overwhelms the thought process?

    Charles described the use of TWO Timers - one configured to capture rising edge - the second to capture falling edge.    The input signal is routed to BOTH Timer pins.   (i.e. it is the SAME signal)

    You ask, "How to implement "Sync" between these two timers.    That's a standard function - available w/in the API - unknown how you've "missed" that.

    The "beauty" of the TWO Timer method is its simplicity - again as Charles (clearly) wrote - the "difference between the Two Timer's latched values, "IS your x1.""

  • Hi Jame,

     I prepare a simple example to demonstrate using two timers to calculate the duty cycle. I was able to measure a duty cycle that is is 0.01% of 1kHz PWM. The timer measures  the duty correctly. You need to modify/adapt to your application. The example calls TimerSynchronize(TIMER0_BASE,TIMER_0A_SYNC|TIMER_0B_SYNC ) to synchronize the two timers. However, since timerA and timerB shares the same timebase, the synchronization should not be needed but you will need if you plan to use between different timer generators. For timerA and timerB that I use from TIMER0, I don't see any difference in the duty cycle with sync or without sync.

    3124.tm4c123_timer_edge_time_mode.zip

  • Hello Charles

    Thank you very much for your answers so far.
    I have corrected the wrong idea.
    Finally, there is two question.

    It was previously described.
    I thought I needed at least 8 cycles to process the ISR jump.
    1. How many cycles do you need to handle the ISR?

    2. What is the maximum period time of detection in input edge count / time mode?

        -  when time module  clock 80 MHz or 40 MHz

    thanks.

  • Hello again Jame,

    First, let me recommend you change one section of your drawings to represent the real signal into two timers. In a few places, you've drawn offset signals going into timers A and B. I have dragged one of them to represent what will actually happen, so that other readers don't get misguided:

    Next, to answer your questions:

    A) How many cycles does the interrupt routine take?

    There are a few manners you can count that:

    1) By measuring the time externally: configure a GPIO pin as output, and before the code block you want to measure, raise it high; right after the block, raise it low. See the signal in a oscilloscope. The time difference is the period those instructions took, PLUS the commands to raise and lower the GPIO (TOTAL_CYCLES). Then, use the same raise/lower instruction right next to each other, and measure that amount of time (TOGGLING_CYCLES). If you subtract the toggling cycles time from the total, you'll get the STUDIED_CYCLES time. Note that code optimization will affect it, so you can measure with optim turned off for a worst case.

    2) Looking at the assembly code of your complete block, and adding by hand the instruction cycles taken by each assembly instruction.

    3) Instead of using GPIO, configure a wide timer to run continuously, sourced by system clock. Before the code block, read the free-running timer value. After the code block, do it again. Note the difference in cycles. As with the GPIO concept, subtract the amount of cycles taken by two adjacent timer read instructions.

    4) Some more powerful IDE's have features that tell you how many cycles a given block requires.

    B) What is the maximum period of detection that the system can measure:

    I'd say this is a good question for you to calculate and respond. Given that this thread has been a extensive study of timers for you - and maybe to others in the future - do you agree that this answer will serve as a final exercise? Do your maths and propose an answer here, I'm sure we'll be able to take a look and guide a correction if needed.

    Bruno

  • *** LIKE *** Notable - the simplicity which your (pardon) "KISS-Based" Drawing provides!     Good that.    

    Sometimes the fledgling needs to be "pushed" from the nest.     (Momma birds are good @ that - forum folk - maybe, "not so much..."

    Any post titled, "I need" shows minimal care/concern for "all others" - and as the "Timer-Sync function" is well listed/described w/in the API - yet  "escaped the note of the "needy" - much of the proclaimed "need" is self-induced - is that not true?       Undue "hand-holding" may result in the fledgling's "never leaving!"      (unwise in both the "bird & forum" kingdoms...)

  • Jame shin said:
    I thought I needed at least 8 cycles to process the ISR jump.

    Common misunderstanding: new programmers tend to confuse the value returned by TimerValueGet(). That can be partly (fully?) to blame on the TivaWare User Guide, which says:

    "This function reads the current value of the specified timer." - such is UNTRUE! The code for that function is:

    return((ui32Timer == TIMER_A) ? HWREG(ui32Base + TIMER_O_TAR) : HWREG(ui32Base + TIMER_O_TBR));

    Register TIMER_O_TAR (or in other words GPTM_TAR) full description:

    "This register shows the current value of the Timer A counter in all cases except for Input Edge Count and Time modes. In the Input Edge Count mode, this register contains the number of edges that have occurred. In the Input Edge Time mode, this register contains the time at which the last edge event took place"

    It DOES NOT MATTER how many cycles your system takes to get into the ISR. When you get there and obtain the timer value, such value will reflect that "old" instant in which your signal transition happened.

    Bruno

  • Hi Jame,

    1) I never said it takes 8 CPU cycles to get to the interrupt. I took your application use case (1kHz input PWM) as a reference and tried to derived how many cycles would be if the duty cycle is 0.01% which is 8 CPU cycles. Then I said 8 cycles will be too short if for the CPU to service the interrupt before the next edge is detected and then overwrite the captured value that has yet to be read by the CPU. If you want to measure how many cycles it takes for the CPU to enter the ISR, this is what I will suggest. You use the same rise edge interrupt. When the edge is detected the timestamp is saved into the GPTMTAV, Immediately in the first instruction inside the ISR you will read the GPTMTAR register. The GPTMTAR is the free-running counter. The difference between these two registers is roughly the time it takes to enter ISR. Note that Bruno has very suggestion too. 

    2) The maximum period depends on your source clock frequency and whether you use 16bit, 24-bit, 32-bit or 48-bit. You simply multiply your CPU clock period by the timer resolution you are using.

  • Charles Tsai said:
    Then I said 8 cycles will be too short if for the CPU to service the interrupt before the next edge is detected and then overwrite the captured value that has yet to be read by the CPU.

    Charles,

    You might be inducting further confusion here... If using the split signal into two timers as suggested, this is NOT a limitation.

    Bruno

  • Hi Bruno,
    Yes, you are correct. Perhaps the poster (or anyone who is following this thread) needs to go back to my original reply for my analysis. When I said it was too short, certainly I meant if one timer solution was used then the captured timestamp for the rise edge will be overwritten by the captured value for the neg edge before it is read.
  • Really  "Time to invoke the Slaughter Rule!"       (are not the helpers - as the thread count  passes FIFTY - now (almost) fighting/arguing?)

    And for WHAT?       The best NEED is SELF-SATISFIED - not "dumped here!"

    Lastly - have you NOT now "OPENED THE DOOR" to "ALL SUCH EXACT EXAMPLE NEEDS" - from "ALL POSTERS?"      (i.e. should EVERY waking moment be devoted to, "I NEED?")      Really?