Pulse width measurement using T4.1 qtimer

bmd1103

Member
I am trying to use a T4.1 to measure the pulse width produced by a TCS230 color light-frequency converter. I am trying to do this using QTIMER ch 1 in Capture mode, with primary source the internal clock and secondary source the sensor output, connected to QTIMER1_TIMER0 on pin 10 (ALT 1).

When I run the code below nothing happens - I get no interrupts although the pulse train is being generated as expected. I also do not get an interrupt on counter overflow. Obviously, I am missing something to do with the interrupt setup but cannot figure out what is wrong.
Any help would be greatly appreciated.



Code is as follows:

Code:
#include <arduino.h>
#include "pins.h"

uint16_t ovflCount, eventCount;
volatile bool tmr1Edgfl, tmr1Ovfl;
volatile uint16_t pulseRise, oldTime;
uint32_t pulseDur[4], intensity[4];

void tmr1_isr()     // TMR1 Interrupt service
{
  if(TMR1_SCTRL1 & TMR_SCTRL_TOF)    // TMR1 Overflow
  {
    TMR1_SCTRL1 &= ~(TMR_SCTRL_TOF);    // reset flag
    tmr1Ovfl = true;
    digitalToggleFast(tp0);  
  }
 
  if(TMR1_SCTRL0 & TMR_SCTRL_IEF)   // TMR1 input edge event
  {
    pulseRise = TMR1_HOLD1;
    TMR1_SCTRL1 &= ~(TMR_SCTRL_IEF);  // Clear  edgeinterrupt flag
    tmr1Edgfl = true;
    digitalToggleFast(tp1);  
  }
  asm volatile ("dsb");  // wait for clear  memory barrier
}

void setup()
{
  Serial.begin(115200);
  pinMode(tp0, OUTPUT);
  pinMode(tp1, OUTPUT);
 
  // Set up QTIMER1 Ch 1 for input capture mode to allow frequency measurement.
  CCM_CCGR6 |= CCM_CCGR6_QTIMER1(CCM_CCGR_ON);

  // Sec source IS QTIMER1 Ch0 input - pin 10 ALT 1.
  IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_00 = 0b0001;    // Pin 10 ALT1 = QTIMER1_TIMER0
 
  TMR1_CTRL1 = 0;     // Stop
  TMR1_CNTR1 = 0;
  TMR1_LOAD1 = 0;
  TMR1_COMP11 = 0;
  TMR1_COMP21 = 0;
  //  Enable overflow and edge detection interrupts
  TMR1_SCTRL1 = (TMR_SCTRL_TOFIE | TMR_SCTRL_IEFIE | TMR_SCTRL_CAPTURE_MODE(2) ) ;
  TMR1_CSCTRL1 = (TMR_CSCTRL_ROC | TMR_CSCTRL_TCI);
  TMR1_CTRL1 = (TMR_CTRL_CM(3) | TMR_CTRL_PCS(8) | TMR_CTRL_SCS(0));
   
  attachInterruptVector(IRQ_QTIMER1, tmr1_isr);

  NVIC_ENABLE_IRQ( IRQ_QTIMER1);
  NVIC_SET_PRIORITY( IRQ_QTIMER1, 64);

  sei();

  Serial.print(" TMR1_CTRL1 = ");Serial.println(TMR1_CTRL1, HEX);
  Serial.print(" TMR1_SCTRL1 = ");Serial.println(TMR1_SCTRL1, HEX);
  Serial.print(" TMR1_CSCTRL1 = ");Serial.println(TMR1_CSCTRL1, HEX);
  Serial.print(" CCM_CCGR6 =  ");Serial.println(CCM_CCGR6, HEX);
  Serial.print(" TMR_ENBL =  ");Serial.println(TMR1_ENBL, HEX);
  Serial.print(" IOMUXC_GPR_GPR2 = ");Serial.println(IOMUXC_GPR_GPR2);

  Serial.println("+++ Setup completed  +++");
  Serial.println("************************");
}

void loop()
{
  Serial.print("  Count = ");Serial.print(TMR1_CNTR1, HEX);Serial.print("  Captured value = "); Serial.print(TMR1_CAPT1, HEX); Serial.print("  TMR1_SCTRL1 = "); Serial.println(TMR1_SCTRL1, HEX);
  delay(100);

  if (tmr1Ovfl)
  {
    Serial.println("Timer 1 Overflow...");
    tmr1Ovfl = false;
  }


  if (tmr1Edgfl)
  {
    Serial.println("Timer 1 Edge detected ...");
    tmr1Edgfl = false;
  }
}
 
Code:
  if(TMR1_SCTRL0 & TMR_SCTRL_IEF)   // TMR1 input edge event
Wrong SCTRL reg specified here.

Timer overflow won't work due to chip errata (ERR050194) - it only works when counting down, not up.
 
Last edited:
Thanks for the tip re ERR050194 - I wasn't aware of that. (The SCTRL issue was a missed change as I did try to see if the system would work any better with the Ch 0 input used as secondary input for Ch1 - there's a reference in the manual for the PCS "NOTE: A timer selecting its own output for input is not a legal choice. The result is no counting.")

I've now modified the code to use "compare to FFFFh" for the overflow detection as per the suggested workaround. I'm now getting very sporadic operation of the edge detect function (once every few seconds with the colour sensor output being toggled about every 900 us.)
C++:
#include <arduino.h>
#include "pins.h"

uint16_t ovflCount, eventCount;
volatile bool tmr1Edgfl, tmr1Ovfl;
volatile uint16_t pulseRise, oldTime;
uint32_t pulseDur[4], intensity[4];

void tmr1_isr()     // TMR1 Interrupt service
{
  // TMR1 Ch0 Overflow
  //  Timer overflow won't work on count up due to chip errata (ERR050194)
  //  Workaround is to use compare function with target 0xffff
  if(TMR1_CSCTRL0 & TMR_CSCTRL_TCF1)   
  {
    TMR1_CSCTRL0 &= ~(TMR_CSCTRL_TCF1);    // reset flag
    tmr1Ovfl = true;
    digitalToggleFast(tp0);   
  }
 
  if(TMR1_SCTRL0 & TMR_SCTRL_IEF)   // TMR1 Ch0 input edge event
  {
    pulseRise = TMR1_HOLD1;
    TMR1_SCTRL0 &= ~(TMR_SCTRL_IEF);  // Clear  edgeinterrupt flag
    tmr1Edgfl = true;
    digitalToggleFast(tp1);   
  }
  asm volatile ("dsb");  // wait for clear  memory barrier
}

void setup()
{
  Serial.begin(115200);
  pinMode(tp0, OUTPUT);
  pinMode(tp1, OUTPUT);
 
  // Set up QTIMER1 Ch 0 for input capture mode to allow frequency measurement.
  CCM_CCGR6 |= CCM_CCGR6_QTIMER1(CCM_CCGR_ON);

  // Sec source IS QTIMER1 Ch0 input - pin 10 ALT 1.
  IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_00 = 0b0001;    // Pin 10 ALT1 = QTIMER1_TIMER0
 
  TMR1_CTRL0 = 0;     // Stop
  TMR1_CNTR0 = 0;
  TMR1_LOAD0 = 0;
  TMR1_COMP10 = 0xffff;
  TMR1_COMP20 = 0;
  //  Enable compare and edge detection interrupts
  TMR1_SCTRL0 = (TMR_SCTRL_TCFIE | TMR_SCTRL_IEFIE | TMR_SCTRL_CAPTURE_MODE(2) ) ;
  TMR1_CSCTRL0 = (TMR_CSCTRL_ROC | TMR_CSCTRL_TCI | TMR_CSCTRL_TCF1EN);
  TMR1_CTRL0 = (TMR_CTRL_CM(3) | TMR_CTRL_PCS(8) | TMR_CTRL_SCS(0));
    
  attachInterruptVector(IRQ_QTIMER1, tmr1_isr);

  NVIC_ENABLE_IRQ( IRQ_QTIMER1);
  NVIC_SET_PRIORITY( IRQ_QTIMER1, 64);

  sei();

  Serial.print(" TMR1_CTRL0 = ");Serial.print(TMR1_CTRL0, HEX);Serial.println("h");
  Serial.print(" TMR1_SCTRL0 = ");Serial.print(TMR1_SCTRL0, HEX);Serial.println("h");
  Serial.print(" TMR1_CSCTRL0 = ");Serial.print(TMR1_CSCTRL0, HEX);Serial.println("h");
  Serial.print(" CCM_CCGR6 =  ");Serial.print(CCM_CCGR6, HEX);Serial.println("h");
  Serial.print(" TMR_ENBL =  ");Serial.print(TMR1_ENBL, HEX);Serial.println("h");
  Serial.print(" IOMUXC_GPR_GPR2 = ");Serial.print(IOMUXC_GPR_GPR2, HEX);Serial.println("h");

  Serial.println("+++ Setup completed  +++");
  Serial.println("************************");
}

void loop()
{
//  Serial.print("  Count = ");Serial.print(TMR1_CNTR0, HEX);Serial.print("  Captured value = "); Serial.print(TMR1_CAPT0, HEX); Serial.print("  TMR1_SCTRL0 = "); Serial.println(TMR1_SCTRL0, HEX);
//  delay(100);

  if (tmr1Ovfl)
  {
    Serial.println("Timer 1 Overflow...");
    tmr1Ovfl = false;
  }
 
  if (tmr1Edgfl)
  {
    //Serial.println("Timer 1 Edge detected ...");
  //  Serial.print(micros());Serial.print("  Capture reg = ");Serial.println(TMR1_CAPT0);
    tmr1Edgfl = false;
  }
}

If I uncomment the Serial.print line on edge detection, I get a fairly random series of microsecond values, with a capture value of 1.

I'll go back and have a very careful read of the manual o see if I can get any clues from that ...
 
Sorted - a whisker-joint hardware problem, also with the "compare to FFFFh" overflow fix I had to clear both TMR_CSCTRL_TCF1 and
TMR_SCTRL_TCF interrupt flags.
 
Back
Top