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.
Tool/software:
Hello,
I am using the GPT timer to capture a pulse width. Two timers are being involved I set up both GPTTImers to capture both edges of the pulse and then I calculated the delta of the first edge and second edge. I have a TX line that will be enabled after both timers are set up. The Tx line is going to two identical capacitors, with the ends of each capacitor going to different rx gpios. Since the signal of the RX is the same, the generated interrupts should happen simultaneously, but it seems like only one interrupt is actually being generated, not both.
Thanks,
Kenneth T.
Hello Kenneth,
Would you be able to provide a basic code file which demonstrates your GPTimer setup and could help us replicate the issue you're describing? Is the same GPTimer interrupt called, or can it vary between the two? If one is disabled then will the other interrupt always be serviced? Does the same behavior occur if using 3.3V power supply levels?
Are you using the TI Driver, driverlib, or direct hardware register access? What can you gather by debugging the register interrupt status of your timers? Also, what version of the F2 SDK are you evaluating?
Regards,
Ryan
vector<GPTimerCC26XX_Handle> gptimer_handles(2); for (size_t t = 0; t < 2; t++) { // Configure GPTimer for edge time capture GPTimerCC26XX_Params gptimer_params; GPTimerCC26XX_Params_init(&gptimer_params); gptimer_params.width = GPT_CONFIG_16BIT; gptimer_params.mode = GPT_MODE_EDGE_TIME; gptimer_params.matchTiming = GPTimerCC26XX_SET_MATCH_NEXT_CLOCK; gptimer_params.direction = GPTimerCC26XX_DIRECTION_UP; gptimer_params.debugStallMode = GPTimerCC26XX_DEBUG_STALL_OFF; // Open GPTimer and set argument to "this" object for callback to use GPTimerCC26XX_Handle gptimer_handle = GPTimerCC26XX_open(t, &gptimer_params); gptimer_handles[t] = gptimer_handle; GPTimerCC26XX_setArg(gptimer_handle, this); // Configure Gpio for edge interrupt if (t == 0) { gpio.configure(Gpio::PinId::DIO_16, Gpio::Direction::INPUT, Gpio::Pull::NONE, Gpio::State::NONE, Gpio::Strength::NONE, GPTimerCC26XX_getPinMux(gptimer_handle)); } else if (t == 1) { gpio.configure(Gpio::PinId::DIO_1, Gpio::Direction::INPUT, Gpio::Pull::NONE, Gpio::State::NONE, Gpio::Strength::NONE, GPTimerCC26XX_getPinMux(gptimer_handle)); } // Set load value in order to support full/max 24-bit capability, configure edge mode and register callback GPTimerCC26XX_setLoadValue(gptimer_handle, MAX_GPTIMER_COUNT); GPTimerCC26XX_setCaptureEdge(gptimer_handle, both_edges ? GPTimerCC26XX_BOTH_EDGES : (rising_edge ? GPTimerCC26XX_POS_EDGE : GPTimerCC26XX_NEG_EDGE)); GPTimerCC26XX_registerInterrupt(gptimer_handle, gptimerCallback, GPT_INT_CAPTURE); GPTimerCC26XX_start(gptimer_handle); } tx_gpio.writeHigh(); for (size_t t = 0; t < 2; t++) { first_edge_sem.wait(); } for (size_t t = 0; t < 2; t++) { _second_edge_sem.wait(); } tx_gpio.writeLow(); for (size_t t = 0; t < 2; t++) { // Stop and close GPTimer GPTimerCC26XX_unregisterInterrupt(gptimer_handles[t]); GPTimerCC26XX_stop(gptimer_handles[t]); GPTimerCC26XX_close(gptimer_handles[t]); }
void Timer::gptimerCallback(GPTimerCC26XX_Handle gptimer_handle, GPTimerCC26XX_IntMask interruptMask) { // Capture edge value Timer* timer = reinterpret_cast<Timer*>(GPTimerCC26XX_getArg(gptimer_handle)); if (timer->_edge_count == 0) { timer->_first_edge_gpt = GPTimerCC26XX_getValue(gptimer_handle); timer->_first_edge_sem.post(); } else if (timer->_edge_count == 1) { timer->_second_edge_gpt = GPTimerCC26XX_getValue(gptimer_handle); timer->_second_edge_sem.post(); } timer->_edge_count++; }
Hi Kenneth,
Thank you for these details. It will take me a while to find the time to replicate and debug this behavior. As additional debug information, is it the same GPTimer interrupt that is always called (i.e. the other is always ignored) and which is which? Is the issue mitigated if using separate callbacks (gptimerCallback) for each GPTimer?
Regards,
Ryan
Hey Ryan,
It looks like both interrupts are being generated but one is being ignored. It is the same GPTtime interrupt that is being ignored and the same interrupt that is being processed. I tried using separate callbacks and doing the pulse capture in different threads for each GPTimer.
Thanks,
Kenneth
Hey Kenneth,
Can you please critique my code setup for any register-level or core functional differences?
/* * Copyright (c) 2016-2020, Texas Instruments Incorporated * All rights reserved. * * 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. */ /* * ======== timerled.c ======== */ #include <stddef.h> #include <unistd.h> /* Driver Header files */ #include <ti/drivers/GPIO.h> #include <ti/drivers/timer/GPTimerCC26XX.h> /* Board Header file */ #include "ti_drivers_config.h" #define MAX_GPTIMER_COUNT 16777215 GPTimerCC26XX_Handle GPTimer0; GPTimerCC26XX_Handle GPTimer1; uint8_t timerCount0 = 0; uint8_t timerCount1 = 0; void gptimerCallback(GPTimerCC26XX_Handle handle, GPTimerCC26XX_IntMask interruptMask) { // interrupt callback code goes here. Minimize processing in interrupt. if (handle == GPTimer0) { timerCount0++; } else if (handle == GPTimer1) { timerCount1++; } } /* * ======== mainThread ======== */ void *mainThread(void *arg0) { /* Call driver init functions */ GPIO_init(); /* Configure the LED pin */ GPIO_setConfig(CONFIG_GPIO_LED_0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW); /* Turn off user LED */ GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_OFF); GPTimerCC26XX_Params gptimer_params; GPTimerCC26XX_Params_init(&gptimer_params); gptimer_params.width = GPT_CONFIG_16BIT; gptimer_params.mode = GPT_MODE_EDGE_TIME; gptimer_params.matchTiming = GPTimerCC26XX_SET_MATCH_NEXT_CLOCK; gptimer_params.direction = GPTimerCC26XX_DIRECTION_UP; gptimer_params.debugStallMode = GPTimerCC26XX_DEBUG_STALL_OFF; // Open GPTimer and set argument to "this" object for callback to use GPTimer0 = GPTimerCC26XX_open(CONFIG_GPTIMER_0, &gptimer_params); GPTimer1 = GPTimerCC26XX_open(CONFIG_GPTIMER_1, &gptimer_params); GPTimerCC26XX_setArg(GPTimer0, (void *)0x00); GPTimerCC26XX_setArg(GPTimer1, (void *)0x01); GPTimerCC26XX_setLoadValue(GPTimer0, MAX_GPTIMER_COUNT); GPTimerCC26XX_setCaptureEdge(GPTimer0, GPTimerCC26XX_BOTH_EDGES); GPTimerCC26XX_registerInterrupt(GPTimer0, gptimerCallback, GPT_INT_CAPTURE); GPTimerCC26XX_start(GPTimer0); GPTimerCC26XX_setLoadValue(GPTimer1, MAX_GPTIMER_COUNT); GPTimerCC26XX_setCaptureEdge(GPTimer1, GPTimerCC26XX_BOTH_EDGES); GPTimerCC26XX_registerInterrupt(GPTimer1, gptimerCallback, GPT_INT_CAPTURE); GPTimerCC26XX_start(GPTimer1); GPIO_setConfigAndMux(CONFIG_GPIO_0, GPIO_CFG_IN_PU, GPTimerCC26XX_getPinMux(GPTimer0)); GPIO_setConfigAndMux(CONFIG_GPIO_1, GPIO_CFG_IN_PU, GPTimerCC26XX_getPinMux(GPTimer1)); while(1) { sleep(10); } return (NULL); }
Both timers are being serviced by the same interrupt, as I can see both timerCount values incrementing, but I am simply pulling down two GPIOs shorted to GND with one switch(i.e. no capacitors) and am operating at 3.3V so I'm not sure whether any of these variables are causing the observable difference.
Regards,
Ryan
Hey Ryan,
Do you happen to know the pulse width of the pulse that is being created? From our observations, it seems that if the pulse width of both pulses is around 10-12 microseconds it seems to have this issue but if it has a pulse width of 490-500 microseconds both interrupts seem to be serviced properly.
Thanks,
Kenneth
I've modified my code and am now the pulse width is 20 microseconds, however the result is still successful.
You could be observing a race condition given that four interrupts have to occur during this time (up and down for each input) and are processed by the same HWI function (GPTimerCC26XXHwiFxn in CPTimerCC26XX.c). It's plausible that the first edge of the first timer surpasses 10 microseconds and thus the second edge of the first timer is processed next instead of the first edge of the second timer. What I'm unclear on is whether the first or second edge of the second timers ever trigger the HWiFxn, but it causes at least one gptimerCallback interrupt service routine to be overwritten/skipped.
I do not believe the GPTimer TI Driver was intended for this type of operation. Can you try reducing the processing in your gptimerCallback as a test and comment on whether that improves the behavior? You may need to modify CPTimerCC26XX.c or use it as reference to create your HWI independently of the TI Driver to further reduce the time spent processing interrupts.
Regards,
Ryan
Hey Ryan,
Sorry for the late reply. I got pulled away from another project. We decided to eventually do the pulse capturing sequentially and then moved it into the sensor controller for better power consumption.
Thanks,
Kenneth T.