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.

PWM measurement using Edge Time Capture

Other Parts Discussed in Thread: EK-TM4C123GXL, TM4C123GH6PM

Hi, I'm using the EK-TM4C123GXL with CCS version 6.1 and Tivaware version 2.1.0 to try and measure the duty cycle of a 1kHz pwm signal from a Senseair S8 CO2 sensor connected to pin PB6. I'm using timer0A and timer0B in edge time mode with A on positive edges and B on negative edges. What I'm trying to do is have an interrupt that records the time of the positive edge, then the negative edge(using TimerValueGet), then finds the difference and outputs through UART

Originally I had the interrupt occur on TIMER_CAPB_EVENT, but when that was the case, I wasn't receiving values for the positive edge(timer A) or the negative edge(timer B) and there was no output through UART at all. I changed the interrupt source to TIMER_CAPA_EVENT, and now I'm getting values for only the positive edge on timer A. It seems that timer B isn't recording a value for the negative edge, but I am getting a UART output (which is negative, because the timer B register is 0)

Am I messing something up somewhere? I would appreciate some help.

Thanks,

Here's my code:

//includes
#include <stdint.h> // Variable definitions for the C99 standard.
#include <stdio.h> // Input and output facilities for the C99 standard.
#include <stdbool.h> // Boolean definitions for the C99 standard.
#include "inc/tm4c123gh6pm.h" // Definitions for the interrupt and register assignments.
#include "inc/hw_memmap.h" // Memory map definitions of the Tiva C Series device.
#include "inc/hw_types.h" // Definitions of common types and macros.
#include "driverlib/sysctl.h" // Definitions and macros for System Control API of DriverLib.
#include "driverlib/interrupt.h" // Defines and macros for NVIC Controller API of DriverLib.
#include "driverlib/gpio.h" // Definitions and macros for GPIO API of DriverLib.
#include "driverlib/timer.h" // Defines and macros for Timer API of DriverLib.
#include "driverlib/pin_map.h" //Mapping of peripherals to pins for all parts.
#include "driverlib/uart.h" // Definitions and macros for UART API of DriverLib.
#include "driverlib/adc.h" // Definitions for ADC API of DriverLib.
#include "driverlib/fpu.h" // Prototypes for the FPU manipulation routines.
#include "utils/uartstdio.h" // Prototypes for the UART console functions.
							 // Needs to add "utils/uartstdio.c" through a relative link.
//definitions
#define UART1_BAUDRATE		115200	// UART baudrate in bps

// function prototypes
void init_timer(void);
void duty_cycle(void);
void init_UART(void);

// global variables
uint32_t sys_clock;
uint32_t  start = 0, end = 0, length = 0;

int main(void)
{
	// Configure system clock at 40 MHz.
	SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
	sys_clock = SysCtlClockGet();

	// Enable the processor to respond to interrupts.
	IntMasterEnable();

	init_UART();
	init_timer();

	TimerEnable(TIMER0_BASE, TIMER_BOTH);

	while(1);
}

void init_timer(void)
{
	// Enable and configure Timer0 peripheral.
	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);

	// Initialize timer A and B to count up in edge time mode
	TimerConfigure(TIMER0_BASE, (TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_TIME_UP | TIMER_CFG_B_CAP_TIME_UP));

	// Timer a records pos edge time and Timer b records neg edge time
	TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_POS_EDGE);
	TimerControlEvent(TIMER0_BASE, TIMER_B, TIMER_EVENT_NEG_EDGE);

	//set the value that the timers count to (0x9C3F = 39999)
	//CO2 sensor outputs 1khz pwm so with mcu at 40Mhz, timers should stay in sync with CO2 output
	TimerLoadSet(TIMER0_BASE, TIMER_BOTH, 0x9C3F);

	//Configure the pin that the timer reads from (PB6)
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
	GPIOPinConfigure(GPIO_PB6_T0CCP0);
	GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_6);


	// Registers a interrupt function to be called when timer b hits a neg edge event
	IntRegister(INT_TIMER0A, duty_cycle);
	// Makes sure the interrupt is cleared
	TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT);
	// Enable the indicated timer interrupt source.
	TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT);
	// The specified interrupt is enabled in the interrupt controller.
	IntEnable(INT_TIMER0A);
}

//When negative edge is hit, record the values and find the difference, output to putty
void duty_cycle(void)
{
	TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT);
	start = TimerValueGet(TIMER0_BASE, TIMER_A);
	end = TimerValueGet(TIMER0_BASE, TIMER_B);
	length = end - start;

	UARTprintf("\nLENGTH = %d\n", length);
}

void init_UART(void)
{
	// Enable and configure UART0 for debugging printouts.
	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
	GPIOPinConfigure(GPIO_PA0_U0RX);
	GPIOPinConfigure(GPIO_PA1_U0TX);
	GPIOPinTypeUART(GPIO_PORTA_BASE, (GPIO_PIN_0 | GPIO_PIN_1));
	UARTStdioConfig(0, UART1_BAUDRATE, sys_clock);
}


  • Hello Ovie,

    You have configured only CCP0 pin for Timer A. The CCP1 pin corresponding to Timer B is not configured. Also the incoming PWM signal has to be connected to both CCP0 and CCP1 pins.

    Regards
    Amit
  • Yup that was my problem. I'm happy the solution was so simple! Thank you!
  • Hi Amit,

    Good job - that "dual connection" of the (same) signal to multiple timer input pins is (often) missed. (thus your advice much exceeds "simple.")

    Amit - might you comment upon use of, "Edge Time Capture" vs. "Edge Count Capture" to achieve similar measurement capabilities? My "first pass" assessment is that both are similar and thus maybe the tendency to "over-flow" dictates use. Your guidance would be helpful and appreciated. (and never noted as "simple")
  • Hello cb1

    As we had discussed quite a few threads back, and based on your suggestion for fast signals "Edge Time Capture" is better as it will be sampled by the timer without CPU delay. On the other hand when capturing slow moving signals that may exceed the 16-bit timer value (And prescalar as well), "Edge Count Capture" would be preferred where another 32-bit timer used along side the capture event to read the time value. There would be some loss of accuracy due to the CPU delay in reading the 32-bit timer value, but this would be rather too small compared to the overall time period of the edges.

    Regards
    Amit
  • Hi Amit,

    Yes - now I recall (you are 1000x more active than I - yet your recall is superior)!

    That said - in the more "general, middle range" (neither very fast nor very slow) might you favor one method (Edge Time vs. Edge Count) over the other? (and if so - which one?) Merci...
  • Hello cb1,

    Good point. It would depend on the what the mid range is defined as and what the accuracy is being sought. If it is accuracy then Edge Time but if the mid range is close to 1 edge in 24-bit *** (16 value and 8 prescalar) then Edge Count. But then that is a case by case basis.

    Regards
    Amit
  • Hi Amit,

    Good - again much thanks - as always your "on-going" efforts are appreciated.

    Appears cb1 is not (quite) as dumb as young staff believes (hopes) and there is "not" a general "Go to" solution but "case by case." Ratz!

    One thing I did miss (staff did not) was relative Programming Ease & Execution Time of each method.   (as you know - helps to be surrounded by those smarter...)

    If time allows - I'll "get even" by assigning this - force crue to employ "both means" for a mid-range (non extreme) solution - and then report back to you. (and to others here - if there is demand... doubtful...)

  • Hello cb1

    Your efforts and thought process are much appreciated.

    Regards
    Amit
  • Hi, very interesting the post,

    but if I want use only one pin for measure the pulse width?, exist any form to identify wich edge is detected, if positive or negative edge when i am inside the interrupt routine?

    I configure to interrupt over both edges, and i want to identify the responsible edge of interrupt inside of interrupt. How do yoy do this?

    Thanks!

  • Fernando Liozzi said:
    but if I want use only one pin for measure the pulse width?

    And - but if those here do not wish to invest 30+ "back/forth" to drag you to a solution - what then?

    Why is this a requirement - the ARM MCU has multiple timers, multiple pins - you are trading a, "known solution" for uncertainty, new effort & delay.   And for what - what's the point - is it really important?   (you've made NO/ZERO "case" for your wish!)

  • Hi cb1_mobile,
    I need to read an ultrasonic sensor HC - SR04 (www.micropik.com/.../HCSR04.pdf). With pic microcontroller, when an interrupt occur by input capture, I can detect if the interrupt was due to positive or negative edge, using only one pin for the echo. With Tiva I interrupt every positive or negative edge, but in the interrupt I do not know if it was due to a positive or negative edge.
    Thanks.
  • Fernando,

    I am not so sure that a PIC maintains a registry to inform that the GPIO transition was rising or lower... Are you sure??? Still, what happens if an opposite transition happened shortly after that one?
    It appears to me that it is more of a software API implementation.
    Anyway, a few engineering options:
    - If your signal is not "too fast", enable the interrupt for both directions, and simply read the GPIO level when servicing the interrupt.
    - If the signal is faster than this can take, use DMA to transfer the GPIO level at the moment of interrupt to a storage location...
    - Or use the brillilant/simple cb1 solution: split the signal into two TCCP pins, and configure one for rising transition and the other for lowering.

  • Bruno Saraiva said:
    Or use the brilliant/simple cb1 solution: split the signal into two TCCP pins - configure one (rising) transition - other lowering.

    Hello - Testing - 1, 2, 3.    GOOD - OK Bruno - we ARE (now) on the "private" forum!    (No one else can view) - your check - as promised - is  "in the mail."   Merci...

  • cb1_mobile said:
    your check - as promised - is  "in the mail."

    It is not that I don't trust you, but only to comply with our ISO9000 procedures, can you please send me a tracking number?

  • Bruno - Bruno - Bruno...   Of course - the requested "Tracking number" has been (reportedly), "Lost in the mail!"  

    Suspect the "single transition detecting" Postal Machine  (that warrants a "Like," mais oui?) ATE your check.   (Hate when that happens!)   You DO have insurance - have you not?

  • Thanks, I have been looking at some register of the TM4C123GH6PM if you can know because of which flank the interruption was due, but I did not find anything. Greetings again and thank you very much.
    Best regards,
    Fernando.
  • My friend - it would appear your "Search Tactics" may require (some) revision.

    You will immensely aid your efforts by finding, then reading, understanding & complying with the simply terrific GUIDANCE provided w/in the, "SW-DRL-UG" (User's Guide for the Peripheral Driver Library).   (name may have changed - yet this gets you "close.")

    If I may - I import from that very document - GPIO Chapter - focused upon Interrupts:

    Again - avoid the use of "JUST ONE" pin - instead - get your TWO PIN method to work!   Only then - invite "Pain/Suffering" to your table - in the attempt to "Save ONE Pin."

    As (somewhat) successful small, tech biz owner - may I note that, "FEW will beat a path to your door for that "One Pin's" Saving!"    Really - no one CARES!    

    Allez!

  • cb1_mobile said:
    Really - no one CARES!

    Unless your schematic looks kind of like this:

    Still, PD2 is also taken on the next revision (tied to GND for "automatic board revision detection").

  • That's the "unfortunate" result of "imperfect planning" and/or "feature creep" - is it not?

    In firm's/my work w/"VC's" (Venture Capitalists) an "acceptable" design is one which ALWAYS allows for those "extra pins" - most often only discovered after field trials - or competitive inroads - demand added capability.

    Schematic you present really, "Fails to provide for "predictable" expansion of needs/requirements!"

    Adding substantial effort (i.e.One pin-edge) - which could have (and should have) been avoided - is not justification - nor a "fair trade" - for clearly, "imperfect" planning!

  • cb1_mobile said:
    Fails to provide for "predictable" expansion of needs/requirements!

    Are you trying to hurt my feelings, oh mighty cb1???? Beware, for I shall hit "unlike" on thy post!

    Plenty of excuses/justifications:

    - Space contraints: it was a challenge to add all those features on the available space! Absolutely zero chance of jumping to the next size chip - nor would I venture BGA at this stage in life!

    - Predictable expansion requirements... guess what, my friend? This is revision E! Trust me when I say it has lots of expansions from the first revision, and yet there is PD2 there available for an extra taster!

    - B wanted to prove that this project was feasible with that P/N

    - B chose this P/N and he is the boss and he does not care for cb1's arguments.

    I can probably come up with further arguments/impositions if required... :)

  • You are arguing w/"specifics" - my attempt is to offer "best practice" general guidelines - which my (fairly) broad experience teaches - will have value to "many" here.

    You are free to accept or reject such suggestions - staff/myself "fail to see" anything "mighty" in offering, "Provide for future expansion!"    Do you advocate - instead - that posters here (always) employ the smallest chip possible - with no expansion capability?  (that's what your approach reduces to - does it not?)   That approach - as you surely know - is indefensible! 

    Again - I've really little concern for your "care" - you should note that my (legal) training avoids personal attack - focuses upon the "sin" - not the sinner!    A new poster arrived here - staff/I felt he was "overly complicating" through use of single Timer pin - and said so!    And you (then) AGREED!    

    Later you introduced your "highly specific case" - which I believe to be a (very) shallow (far too limited) defense.   Providing for expansion - for all but the absolutely "locked-down" - high volume designs - is clearly "best practice!"   (Liked or not!)

    I do my best to serve many - have done so here/elsewhere for many years - and have garnered a nice stable of loyal clients through these efforts...   Your arrival has been nicely noted - I've "liked" multiple of your writings - yet it proves very difficult to, "defend the indefensible."

  • Good Friday, cb1!

    This is a risk of written communication: you can't see the smile on writer's face, and for some reason assume there is an embedded attack in between those lines... As an act of white flagging, be it said that I posted the "specific case pinfull schematic" with:

    - A smile, and awareness that it could pick on my fellow and estimated cb1

    - The intention of filling in yet one more example - for even that specific situation might be the reality of certain projects, and it is probably of benefit to thrown in an example or two where pins are running out...

    - Maybe (assuming my humanly condition) to show off my cool schematic :) where almost all pins were occupied (better word than "used", because a couple of sensors there are still just sitting on the board, unused).

    And my "defense" later on was just to make sure that readers don't judge such schematic as a bad example, but rather as a real life situation that can happen...

    Hey, thanks again for the welcoming, challenging posts, likes and what not! And also for this mentioning of a nicely noted arrival, it is a honor to read such! 

    Might I confess that on a board we're working at this very moment, we're duplicating not one PWM input, but four of them! That's four extra pins "thrown on the garbage???" for the recognition of such a brilliant, simple and effective idea of dual pin triggering! And your cheque is also on the mail (of course, same courier hired for that one earlier this week...)

    Thanks for all the support! May I be able to help many others here and elsewhere - for there are fewer things that boosts our knowledge than the attempt to teach others!

    Cheers

    Bruno

  • Nicely said/written Bruno - and while your "tongue in cheek" may have been noted - I felt it "my duty" to steer forum users to a (pardon) Safer Harbor.   (as a semi-skilled sailor)

    Firm/my favorite means of, "Welcoming inevitable design expansion (i.e. "feature creep") is via SPI or I2C based, I/O Extenders."   These exact the fewest "pin-load" from the MCU - and if well chosen/implemented - may be "daisy-chained."  (when/where possible - we choose the 16 pin I/O versions of such "extenders" as 2 to 4 MCU pins are (usually) "lost via the interface."   Thus an 8 pin ext. gains just 4 I/O under SPI.)

    Famed poster Robert A. and I both agree that, "Premature Optimization" - while not as "painful" as (other/better known) "early" arrivals - proves both "design inhibiting/delaying" & too often - destructive.   Firm/I have noted multiple client-designers who, "cram usage into (every) MCU "nook & cranny" - believing that to be "optimized."     In reality - that "too early, cram-practice" (presented as "optimization") proves severely limiting.

    Our recent poster's desire for "one & only one Timer pin" registers as good candidate for Robert's, "too early" notation.   Far better to, "Meet the design objective more quickly/easily" - few will (really) care that, "Pins were saved!"  Add that (extra) design time/effort (only) downstream - and only "as/if needed."   (most always - it is NOT!)

    May I note that "rarely" (i.e. never) will a user request, "Feature Reduction" - always the push is for the opposite - and woe be unto those who fail to provide for (both) EFFICIENT/Welcoming signal & software expansion!   Or who optimize - did we (perhaps) note - prematurely?