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.
I am working on a CC2650 application to measure pulse widths in the range of 1us. I found that setting up an edge-triggered interrupt and reading SysTick in the interrupting resulted in highly inaccurate measurements (as well as missed edges) because of the varying delay between the edge and the actual ISR execution.
I read in the tech reference that you can use GPTimers to capture the time that an edge occurred and trigger an interrupt. It looks to me like I need to do the following:
1) Use IOCFGx register to set the GPIO pin for edge detection (both edges) and set PORT EVENT x to be triggered when this happens
2) Set up two GPTimers for edge capture - one set for rising edge, one for falling.
Where I am confused, is in the how to map EVENT x to the GPTimer edge trigger. It looks like the MCU event fabric is the place to do this, but I can't make sense of the mapping.
I'm also wondering if can configure TWO timers to track edge events for the SAME input signal, one capturing rising edges, the other capturing falling edges.
Any help here, or example code, would be helpful.
Hi Todd,
The way you potentially could achieve this would be:
I do not know the timer very well but I think it is the IO's which sets the limitation on minimum periods of a signal being detected. You might be able to get around it by connecting the signal to two different IO's and have one detect a rising and one a falling event.
The same ISR will be taken and returned to the user from the PIN driver if the PIN handle has configured a callback function to do so.
Regards,
Svend
Svend,
Thanks for your help! I am able to successfully trigger interrupts on the rising/falling edge of my input signal, but for some reason, I can't seem to get the timers to capture the clock value at the moment the edge occurred - it always reads zero.
I'm tying together GPIO pins 26 and 27 and using the former for positive edges, the later for falling Here is my initialization sequence:
// Set inputs for edge detection
HWREG(IOC_BASE + IOC_O_IOCFG26) |= (IOC_IOCFG26_EDGE_DET_POS | IOC_IOCFG26_PORT_ID_PORT_EVENT0);
HWREG(IOC_BASE + IOC_O_IOCFG27) |= (IOC_IOCFG27_EDGE_DET_NEG | IOC_IOCFG27_PORT_ID_PORT_EVENT1);
// Set the pins to trigger PORT_EVENT0 and PORT_EVENT1 respectively
PINCC26XX_setMux(hPinHandle, Board_VXBOOST_CMP, IOC_PORT_MCU_TIMER0);
PINCC26XX_setMux(hPinHandle, Board_VXBOOST_CMP2, IOC_PORT_MCU_TIMER1);
// Set EVENT0 and EVENT1 to trigger the edge capture of the GP timers.
HWREG(EVENT_BASE + EVENT_O_GPT0ACAPTSEL) = EVENT_GPT0ACAPTSEL_EV_PORT_EVENT0;
HWREG(EVENT_BASE + EVENT_O_GPT0BCAPTSEL) = EVENT_GPT0BCAPTSEL_EV_PORT_EVENT1;
// Enable the free-running clock...
HWREG(CPU_SCS_BASE + CPU_SCS_O_STRVR) = 0x00FFFFFF;
HWREG(CPU_SCS_BASE + CPU_SCS_O_STCSR) = 0x01;
// Enable GPT0
HWREG(PRCM_BASE + PRCM_O_GPTCLKGR) |= PRCM_GPTCLKGR_CLK_EN_GPT0;
PRCMLoadSet();
// Sets timers of GPT0 to be edge capture and up-counting timer
TimerConfigure(GPT0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_TIME_UP | TIMER_CFG_B_CAP_TIME_UP);
// Sets timer A to save value on rising edge.
TimerEventControl(GPT0_BASE, TIMER_A, TIMER_EVENT_POS_EDGE);
// Sets timer B to store value on falling edge.
TimerEventControl(GPT0_BASE, TIMER_B, TIMER_EVENT_NEG_EDGE);
// Sync the timers together
TimerSynchronize(GPT0_BASE, TIMER_0A_SYNC | TIMER_0B_SYNC);
// Initialize this to zero.
TimerPrescaleSet(GPT0_BASE, TIMER_BOTH, 0);
// Start at zero
TimerLoadSet(GPT0_BASE, TIMER_BOTH, 0);
// Enable both timers
TimerEnable(GPT0_BASE, TIMER_BOTH);
// Register the interrupts...
TimerIntRegister(GPT0_BASE, TIMER_A, processRisingEdge);
TimerIntRegister(GPT0_BASE, TIMER_B, processFallingEdge);
>>> When we are ready to collect data, the software enables interrupts like this:
// Clear any pending interrupt flags
HWREG(GPIO_NONBUF_BASE+GPIO_O_EVFLAGS31_0) = ( (1 << 27) | (1 << 26));
// Enable the interrupts
TimerIntEnable(GPT0_BASE, TIMER_CAPA_EVENT | TIMER_CAPB_EVENT);
Inside the rising-edge interrupt, I attempt to grab the timer values like this
ticks = ( (HWREG(GPT0_BASE + GPT_O_TAPR) & 0x000000FF) << 16) + HWREG(GPT0_BASE + GPT_O_TAR);
Similarly, in the falling edge interrupt I do this:
ticks = ( (HWREG(GPT0_BASE + GPT_O_TBPR) & 0x000000FF) << 16) + HWREG(GPT0_BASE + GPT_O_TBR);
However, ticks always ends up as zero. Can you spot anything I missed above?
Hi Todd,
Good to hear you have it working but reading through your code I am surprised this works on a system level with TI RTOS. A few comments below:
Todd Witters said:HWREG(IOC_BASE + IOC_O_IOCFG26) |= (IOC_IOCFG26_EDGE_DET_POS | IOC_IOCFG26_PORT_ID_PORT_EVENT0);
HWREG(IOC_BASE + IOC_O_IOCFG27) |= (IOC_IOCFG27_EDGE_DET_NEG | IOC_IOCFG27_PORT_ID_PORT_EVENT1);
This is partially what PIN_setMux is doing as well and enabling interrupts as well should be done through the PIN_Config given to PIN_open.
Todd Witters said:// Enable the free-running clock...
HWREG(CPU_SCS_BASE + CPU_SCS_O_STRVR) = 0x00FFFFFF;
HWREG(CPU_SCS_BASE + CPU_SCS_O_STCSR) = 0x01;
Enabling the SysTick timer is unrelated to the GP Timers so unnecessary, it just uses current.
Todd Witters said:// Enable GPT0
HWREG(PRCM_BASE + PRCM_O_GPTCLKGR) |= PRCM_GPTCLKGR_CLK_EN_GPT0;
PRCMLoadSet();
TI RTOS API Power_setDependency should be used instead.
Todd Witters said:// Register the interrupts...
TimerIntRegister(GPT0_BASE, TIMER_A, processRisingEdge);
TimerIntRegister(GPT0_BASE, TIMER_B, processFallingEdge);
The IntRegister functions in here will copy the vector table from Flash to RAM and patch the vector table in RAM. This will overwrite any interrupts TI RTOS had configured up in RAM already. TI RTOS API Hwi_construct should be used instead.
Also you will need to disallow the system from going to standby when the timers are running using Power_setConstraing(POWER_SB_DISALLOW).
Best regards,
Svend
Hi,Todd Witters
I had a problem,When I call the function "TimerIntRegister() " to register callback function,compiler hints:
"Warning[Lp023]: absolute placement (in [0x20000000-0x200000c7]) overlaps with reserved areas: C:\ti\simplelink\ble_cc26xx_2_00_00_42893\Projects\ble\SimpleBLEPeripheral\CC26xx\IAR\Application\CC2640\..\..\..\..\..\common\cc26xx\IAR\cc26xx_ble_app.icf 139 [0x20000000-0x200000c7] "ti_sysbios_family_arm_m3_Hwi_ramVectors" "
TimerIntRegister(GPT0_BASE,TIMER_A,Timer_callBackFun); // "Timer_callBackFun" is defined by myself.
Can you tell me how to solve this problem?
Hello Svendbt,
Nice to see your post related ti timer implementing for pulse period measurement. I am also struggling with this. I just need to measure the pulse duty (period) in a simple way so that I can understand this step by step, how it works. Please help me by sharing a simple example for this application.
Please suggest~
Thanks n Regards
Hi Todd,
Can you help me about what to include the definition in you code.
For example, i have already include <driverlib/ioc.h> in my code but it still have wrong about IOC_PORT_MCU_TIMER0 for no definition.
Can you help me?
Hi Todd,
1) I try to decrease two ticks from below tickA -tickB.
Do you know what's the meaning of the result.
for example : HEX(0000d6ae - 0000d697) = DEC (23)
Is it meaning 23*(1/48 micro sec) = 0.479 ?
Why it doesn't match the input signal for about 10 micro second.
tickA = ( (HWREG(GPT0_BASE + GPT_O_TAPR) & 0x000000FF) << 16) + HWREG(GPT0_BASE + GPT_O_TAR);
tickB = ( (HWREG(GPT0_BASE + GPT_O_TAPR) & 0x000000FF) << 16) + HWREG(GPT0_BASE + GPT_O_TAR);
2) Do you know the difference between
( (HWREG(GPT0_BASE + GPT_O_TAPR) & 0x000000FF) << 16) + HWREG(GPT0_BASE + GPT_O_TAR);
and
HWREG(GPT0_BASE + GPT_O_TAR);
best regards,
Anna