Teensyduino 1.48 Beta #3

Status
Not open for further replies.
@KurtE
Did some experimenting using loopback and pin 14 for the Rx pin. In our lib I added IOMUXC_QTIMER3_TIMER2_SELECT_INPUT = 0x01; //pin 14 to the begin function and it hung the T4 - then it would loose connection to the usb.

So as a test I modified @manitou's original standalone pulsepositioninput sketch to use pin 14 for tx and used the lib functions for transmitting on pin 9 and it worked like a charm - output: 600.03 input: 600.08. Heres the sketch modified to use pin 14 for rx:
Code:
// PPM in, report pulse widths
//  test with PulsePosition output pin 9 to T4 pin 11
// QTIMER1   pin capture test  qtmr 1 ch 2  pin 11 B0_02,  ch 52
// free-running 16-bit timer
// QTIMER oflow interrupt no workee,  use 0xffff compare for 32-bit
// polarity TMR_SCTRL_IPS
#define PRREG(x) Serial.printf(#x" 0x%x\n",x);
#include <PulsePosition_t4.h>
PulsePositionOutput myOut;

#define PULSEPOSITION_MAXCHANNELS 16
uint32_t pulse_width[PULSEPOSITION_MAXCHANNELS+1];
uint32_t pulse_buffer[PULSEPOSITION_MAXCHANNELS+1];
uint32_t write_index, prev, total_channels;

#define CLOCKS_PER_MICROSECOND (150./4)  // pcs 8+2
#define RX_MINIMUM_SPACE   3500.0
#define RX_MINIMUM_SPACE_CLOCKS   (uint32_t)(RX_MINIMUM_SPACE * CLOCKS_PER_MICROSECOND)


volatile uint32_t ticks, overflow_count;
volatile bool overflow_inc, available_flag;

void my_isr() {  // capture and compare
  if (TMR3_CSCTRL2 & TMR_CSCTRL_TCF1) { // compare rollover
    TMR3_CSCTRL2 &= ~(TMR_CSCTRL_TCF1);  // clear
    overflow_count++;
    overflow_inc = true;
  }
  if (TMR3_SCTRL2 & TMR_SCTRL_IEF) { // capture
    uint32_t val, count;
    TMR3_SCTRL2 &= ~(TMR_SCTRL_IEF);  // clear
    val = TMR3_CAPT2;
    count = overflow_count;
    if (val > 0xE000 && overflow_inc) count--;
    val |= (count << 16);
    count = val - prev;
    prev = val;
    if (count >= RX_MINIMUM_SPACE_CLOCKS) {
      if (write_index < 255) {
        for (int i = 0; i < write_index; i++) {
          pulse_buffer[i] = pulse_width[i];
        }
        total_channels = write_index;
        available_flag = true;
      }
      write_index = 0;
    } else {
      if (write_index < PULSEPOSITION_MAXCHANNELS) {
        pulse_width[write_index++] = count;
      }
    }
  }
  ticks++;
  asm volatile ("dsb");  // wait for clear  memory barrier
  overflow_inc = false;
}

void capture_init() {
  CCM_CCGR6 |= CCM_CCGR6_QTIMER3(CCM_CCGR_ON);

  TMR3_CTRL2 = 0; // stop
  TMR3_LOAD2 = 0;
  TMR3_CSCTRL2 = 0;
  TMR3_LOAD2 = 0;  // start val after compare
  TMR3_COMP12 = 0xffff;  // count up to this val, interrupt,  and start again
  TMR3_CMPLD12 = 0xffff;

  TMR3_SCTRL2 = TMR_SCTRL_CAPTURE_MODE(1);  //rising
  attachInterruptVector(IRQ_QTIMER3, my_isr);
  TMR3_SCTRL2 |= TMR_SCTRL_IEFIE;  // enable compare interrupt
  TMR3_CSCTRL2 = TMR_CSCTRL_TCF1EN;  // enable capture interrupt
  NVIC_SET_PRIORITY(IRQ_QTIMER3, 32);
  NVIC_ENABLE_IRQ(IRQ_QTIMER3);
  TMR3_CTRL2 =  TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | TMR_CTRL_SCS(0) | TMR_CTRL_LENGTH ; // prescale
  *(portConfigRegister(14)) = 1;  // ALT 1
  IOMUXC_QTIMER3_TIMER2_SELECT_INPUT = 0x01;  //pin 14
}

int ppmIn_available() {
  uint32_t total;
  bool flag;

  __disable_irq();
  flag = available_flag;
  total = total_channels;
  __enable_irq();
  if (flag) return total;
  return -1;
}

float ppmIn_read(uint8_t channel) {
  uint32_t total, index, value = 0;

  if (channel == 0) return 0.0;
  index = channel - 1;
  __disable_irq();
  total = total_channels;
  if (index < total) value = pulse_buffer[index];
  if (channel >= total) available_flag = false;
  __enable_irq();
  return (float)value / (float)CLOCKS_PER_MICROSECOND;
}

void setup()   {
  Serial.begin(9600);
  while (!Serial);
  delay(1000);
  myOut.begin(9);  // connect pins 9 and 10 together...
  myOut.write(1, 600.03);
  write_index = 255;
  available_flag = false;
  capture_init();

  PRREG(TMR3_SCTRL2);
  PRREG(TMR3_CSCTRL2);
  PRREG(TMR3_CTRL2);
  PRREG(TMR3_LOAD2);
  PRREG(TMR3_COMP12);
  PRREG(TMR3_CMPLD12);
  PRREG(TMR3_COMP22);
  PRREG(TMR3_CMPLD22);
}

void loop() {
  int i, num;
  static int count = 0;

  // Every time new data arrives, simply print it
  // to the Arduino Serial Monitor.
  num = ppmIn_available();
  if (num > 0) {
    count = count + 1;
    Serial.print(count);
    Serial.print(" :  ");
    for (i = 1; i <= num; i++) {
      float val = ppmIn_read(i);
      Serial.print(val);
      Serial.print("  ");
    }
    Serial.println();
  }
}
 
Last edited:
Re: daisy register
I was lucky in my QTIMER proof-of-concepts, i just tried pins 11 and 6 and didn't stumble on a daisy register. However, in the last few days I've been playing with eflexPWM timers to do PPM input and output, and pin 8 did require a SELECT_INPUT daisy register config. (Paul's T4 FrequencyMeasure uses eflexPWM capture on pin 22 and also requires a daisy register.)

@mjs513, the programming gods are smiling on you: :) TMR_CTRL_SCS(14) should be TMR_CTRL_SCS(2) for pin 14 (QT3_2). Conveniently 14 mod 4 = 2

FWIW, i haven't been able to get PPM out to work with long (> 16bit) pulse width using flexPWM timer. I did get PPM in to work with flexPWM timer (capture and overflow interrupts).
https://github.com/manitou48/teensy4/blob/master/ppminf.ino
 
Last edited:
@manitou - @KurtE

That's what I get for playing with this when I can't sleep at 2 in the morning:) Knew it was channel but still put pin, argh.

Anyway, what to try the input example with different pins outside the lib structure to see if changes would work. Daisy Chain worked for pin 14 but not in the lib. That's one test. The second test I just did was to use pin 13 for input (QT2_0). And unless I forgot to change something doesn't look like pin 13 will work as an input pin unless something else has to change: EDIT: YEP FORGOT the Daisy Chain - once I do that it works as well.
Code:
// PPM in, report pulse widths
//  test with PulsePosition output pin 9 to T4 pin 11
// QTIMER1   pin capture test  qtmr 1 ch 2  pin 11 B0_02,  ch 52
// free-running 16-bit timer
// QTIMER oflow interrupt no workee,  use 0xffff compare for 32-bit
// polarity TMR_SCTRL_IPS
#define PRREG(x) Serial.printf(#x" 0x%x\n",x);
#include <PulsePosition_t4.h>
PulsePositionOutput myOut;

#define PULSEPOSITION_MAXCHANNELS 16
uint32_t pulse_width[PULSEPOSITION_MAXCHANNELS+1];
uint32_t pulse_buffer[PULSEPOSITION_MAXCHANNELS+1];
uint32_t write_index, prev, total_channels;

#define CLOCKS_PER_MICROSECOND (150./4)  // pcs 8+2
#define RX_MINIMUM_SPACE   3500.0
#define RX_MINIMUM_SPACE_CLOCKS   (uint32_t)(RX_MINIMUM_SPACE * CLOCKS_PER_MICROSECOND)


volatile uint32_t ticks, overflow_count;
volatile bool overflow_inc, available_flag;

void my_isr() {  // capture and compare
  if (TMR2_CSCTRL0 & TMR_CSCTRL_TCF1) { // compare rollover
    TMR2_CSCTRL0 &= ~(TMR_CSCTRL_TCF1);  // clear
    overflow_count++;
    overflow_inc = true;
  }
  if (TMR2_SCTRL0 & TMR_SCTRL_IEF) { // capture
    uint32_t val, count;
    TMR2_SCTRL0 &= ~(TMR_SCTRL_IEF);  // clear
    val = TMR2_CAPT0;
    count = overflow_count;
    if (val > 0xE000 && overflow_inc) count--;
    val |= (count << 16);
    count = val - prev;
    prev = val;
    if (count >= RX_MINIMUM_SPACE_CLOCKS) {
      if (write_index < 255) {
        for (int i = 0; i < write_index; i++) {
          pulse_buffer[i] = pulse_width[i];
        }
        total_channels = write_index;
        available_flag = true;
      }
      write_index = 0;
    } else {
      if (write_index < PULSEPOSITION_MAXCHANNELS) {
        pulse_width[write_index++] = count;
      }
    }
  }
  ticks++;
  asm volatile ("dsb");  // wait for clear  memory barrier
  overflow_inc = false;
}

void capture_init() {
  CCM_CCGR6 |= CCM_CCGR6_QTIMER2(CCM_CCGR_ON);

  TMR2_CTRL0 = 0; // stop
  TMR3_LOAD0 = 0;
  TMR2_CSCTRL0 = 0;
  TMR2_LOAD0 = 0;  // start val after compare
  TMR2_COMP10 = 0xffff;  // count up to this val, interrupt,  and start again
  TMR2_CMPLD10 = 0xffff;

  TMR2_SCTRL0 = TMR_SCTRL_CAPTURE_MODE(1);  //rising
  attachInterruptVector(IRQ_QTIMER2, my_isr);
  TMR2_SCTRL0 |= TMR_SCTRL_IEFIE;  // enable compare interrupt
  TMR2_CSCTRL0 = TMR_CSCTRL_TCF1EN;  // enable capture interrupt
  NVIC_SET_PRIORITY(IRQ_QTIMER2, 32);
  NVIC_ENABLE_IRQ(IRQ_QTIMER2);
  TMR2_CTRL0 =  TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | TMR_CTRL_SCS(0) | TMR_CTRL_LENGTH ; // prescale
  *(portConfigRegister(13)) = 1;  // ALT 1
IOMUXC_QTIMER2_TIMER0_SELECT_INPUT = 0x01;  //pin 13
//IOMUXC_QTIMER3_TIMER2_SELECT_INPUT = 0x01;  //pin 14
}

int ppmIn_available() {
  uint32_t total;
  bool flag;

  __disable_irq();
  flag = available_flag;
  total = total_channels;
  __enable_irq();
  if (flag) return total;
  return -1;
}

float ppmIn_read(uint8_t channel) {
  uint32_t total, index, value = 0;

  if (channel == 0) return 0.0;
  index = channel - 1;
  __disable_irq();
  total = total_channels;
  if (index < total) value = pulse_buffer[index];
  if (channel >= total) available_flag = false;
  __enable_irq();
  return (float)value / (float)CLOCKS_PER_MICROSECOND;
}

void setup()   {
  Serial.begin(9600);
  while (!Serial);
  delay(1000);
  myOut.begin(9);  // connect pins 9 and 10 together...
  myOut.write(1, 600.03);
  write_index = 255;
  available_flag = false;
  capture_init();

  PRREG(TMR2_SCTRL0);
  PRREG(TMR2_CSCTRL0);
  PRREG(TMR2_CTRL0);
  PRREG(TMR2_LOAD0);
  PRREG(TMR2_COMP10);
  PRREG(TMR2_CMPLD10);
  PRREG(TMR2_COMP20);
  PRREG(TMR2_CMPLD20);
}

void loop() {
  int i, num;
  static int count = 0;

  // Every time new data arrives, simply print it
  // to the Arduino Serial Monitor.
  num = ppmIn_available();
  if (num > 0) {
    count = count + 1;
    Serial.print(count);
    Serial.print(" :  ");
    for (i = 1; i <= num; i++) {
      float val = ppmIn_read(i);
      Serial.print(val);
      Serial.print("  ");
    }
    Serial.println();
  }
}

EDIT: Interestingly Pin18 works without setting the daisy chain register - probably because its already 0? Pin 19 works but you need to set the IOMUX register.

EDIT1: pin 6 does work as input, but pins 11, 12 do work as input getting the correct values
 
Last edited:
RE: FOUND THE HANG FOR PINS OTHER THAN 11

Hangs on this line:
Code:
	//set Mux for Tx Pin - all timers on ALT1
	*(portConfigRegister(rxPin)) = 1;

Yes I changed pin variable name. Works if you set it to 0 but that was just curiosity.
 
RE: FOUND THE HANG FOR PINS OTHER THAN 11

Hangs on this line:
Code:
	//set Mux for Tx Pin - all timers on ALT1
	*(portConfigRegister(rxPin)) = 1;

Yes I changed pin variable name. Works if you set it to 0 but that was just curiosity.
maybe try *(portConfigRegister(rxPin)) = 1 | 0x10;
 
Good morning...

Yep - I have seen it hang at or near there... Sometimes it goes a bit longer... before hang...
Code:
bool PulsePositionInput::begin(uint8_t pin)
{
	for (idx_channel = 0; idx_channel < _hardware_count; idx_channel++) {
		if (hardware[idx_channel].pin == pin) break; 
	}
	if (idx_channel == _hardware_count) return false;

	// make sure the appropriate clock gate is enabled.
	*hardware[idx_channel].clock_gate_register |= hardware[idx_channel].clock_gate_mask;

	uint8_t channel =  hardware[idx_channel].channel;
	volatile IMXRT_TMR_CH_t *tmr_ch = &hardware[idx_channel].tmr->CH[channel];

	tmr_ch->CTRL = 0; // stop
	tmr_ch->CNTR = 0;
	tmr_ch->LOAD = 0;
	tmr_ch->CSCTRL = 0;
	tmr_ch->LOAD = 0;  // start val after compare
	tmr_ch->COMP1 = 0xffff;  // count up to this val, interrupt,  and start again
	tmr_ch->CMPLD1 = 0xffff;

	if(outPolarity == 0){
	  tmr_ch->SCTRL = TMR_SCTRL_CAPTURE_MODE(2);  //falling
	} else {
	  tmr_ch->SCTRL = TMR_SCTRL_CAPTURE_MODE(1);  //rising
	}
	attachInterruptVector(hardware[idx_channel].interrupt, hardware[idx_channel].isr);
	tmr_ch->SCTRL |= TMR_SCTRL_IEFIE | TMR_SCTRL_TOFIE;  // enable compare interrupt as well as overflow
	// tmr_ch->CSCTRL = TMR_CSCTRL_TCF1EN;  // enable capture interrupt
	NVIC_SET_PRIORITY(hardware[idx_channel].interrupt, 32);
	NVIC_ENABLE_IRQ(hardware[idx_channel].interrupt);
	
//	tmr_ch->CTRL =  TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | TMR_CTRL_SCS(channel) | TMR_CTRL_LENGTH ; // prescale
	tmr_ch->CTRL =  TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | TMR_CTRL_SCS(channel) ; // prescale
	
	list[idx_channel] = this;
	
	//set Mux for Tx Pin - all timers on ALT1
	*(portConfigRegister(pin)) = 1;

	Serial.printf("PulsePositionInput::begin pin:%d idx: %d CH:%d SC:%x CSC:%x\n", pin, idx_channel, channel, tmr_ch->SCTRL, tmr_ch->CSCTRL); Serial.flush();
	Serial.printf("  CP1:%x CP2:%x CAPT:%x LOAD:%x \n", (uint16_t)tmr_ch->COMP1, (uint16_t)tmr_ch->COMP2,
		(uint16_t)tmr_ch->CAPT, (uint16_t)tmr_ch->LOAD); 
	Serial.flush();
	Serial.printf("  HOLD:%x CNTR:%x CTRL:%x  SCTRL:%x\n", (uint16_t)tmr_ch->HOLD, (uint16_t)tmr_ch->CNTR, (uint16_t)tmr_ch->CTRL, (uint32_t)tmr_ch->SCTRL); 
	Serial.flush();

	Serial.printf(" CMPLD1:%x, CMPLD2:%x, FILT:%x DMA:%x ENBL:%x\n",tmr_ch->CMPLD1,
		tmr_ch->CMPLD2, tmr_ch->FILT, tmr_ch->DMA, tmr_ch->ENBL);
	Serial.flush();

	Serial.printf("Select Input Regster: %x %d\n", (uint32_t)hardware[idx_channel].select_input_register, hardware[idx_channel].select_val); Serial.flush();
	if (hardware[idx_channel].select_input_register) {
		*hardware[idx_channel].select_input_register = hardware[idx_channel].select_val;
		Serial.println("Select Input completed");Serial.flush();
	}


	
	return true;
}
That is why I put flush output statements around each of the prints to try to force them out. . Almost always I get the first print...

I have a sort of theory on my test case, that is there is a timing issue... In particular my guess is that maybe I get a pulse on the output before I finish setting up... Again just a guess. My current code sets/clears Pin2 on combined ISR. Does pin 3 on Output ISR and Pin 4 on Input ISR... Will take a look at your stuff again to see if I am missing anything obvious. I will go back to using the match on Input instead of trying to get the overflow to work. I thought one issue might be in overflow that we were setting the TMR_CTRL_LENGTH flag, so I removed it and it did not help.

Also in your last test case, I saw you were using: TMR2_CTRL0 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | TMR_CTRL_SCS(0) | TMR_CTRL_LENGTH ; // prescale
Did the SCS(0) depend on which channel you were testing?

Now to next cup of coffee!
 
FYI - I changed around my test app, to init the In before the Out and sure enough everything prints:
Code:
  myIn.begin(19);
  myOut.begin(9);
  myOut.write(1, 750);
  myOut.write(2, 1500);
  myOut.write(3, 2250);

Code:
PulsePositionInput::begin pin:19 idx: 9 CH:0 SC:1440 CSC:300
Select Input Regster: 401f857c 1
Select Input completed
  CP1:ffff CP2:0 CAPT:0 LOAD:0 
  HOLD:0 CNTR:23e CTRL:3420  SCTRL:1440
 CMPLD1:ffff, CMPLD2:0, FILT:0 DMA:0 ENBL:0

But it hangs as expected on the first Input ISR attempt...
screenshot.jpg
First interrupt is the Output one, which you can see gets processed on the Output ISR handler. But then next ISR request comes in and is NOT processed and we hang... Now to debug
 
maybe try *(portConfigRegister(rxPin)) = 1 | 0x10;

@manitou - tried both ways with no luck - I also tried to set it directly with (IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_01) but that didn't work either. Something strange going on or preventing it from setting.

@KurtE. For my loopback I am just using the example loopback without the addition of pins 2/3. So in my case it always seems to be dying on setting the pin mux for Rx. I did try a test where I just used output on 1 T4 and input on a second T4 and still the same thing except the T4 used for Rx lost USB and hung. Only pin 6 didn't work as an input pin but I was also transmitting on pin 9 which is the same timer.

Now more coffee and try and get some sleep

As for changing SCS(channel) to the appropriate channel. Yep I changed it as I went.
 
The coffee has not kicked in yet, but...

I took the hang from before and added more print out stuff.

So like the code I posted above, it now outputs:
Code:
PulsePositionInput::begin pin:19 idx: 9 CH:0 SC:1440 CSC:300
Select Input Regster: 401f857c 1
Select Input completed
  CP1:ffff CP2:0 CAPT:0 LOAD:0 
  HOLD:0 CNTR:20a CTRL:3420  SCTRL:1440
 CMPLD1:ffff, CMPLD2:0, FILT:0 DMA:0 ENBL:0

I then mucked with my ISR3 function as using pin 19, which is 3-0...
Code:
void PulsePositionBase::isrTimer3()
{
	digitalWriteFast(2, HIGH);
	static uint8_t report_count = 0;
	if (report_count < 10) {
		report_count++;
		Serial1.printf("isrTimer3: %x %x %x %x\n    ", (uint32_t)list[6], (uint32_t)list[7], (uint32_t)list[8], (uint32_t)list[9]);
		for (uint8_t ch=0; ch < 4; ch++) {
			Serial1.printf(" %d: %04x %04x", ch, (uint16_t)IMXRT_TMR3.CH[ch].SCTRL,  (uint16_t)IMXRT_TMR3.CH[ch].CSCTRL);

		}
		Serial1.println();
	}
	if (list[6] && TimerCHInPending(&IMXRT_TMR3.CH[2])) { list[6]->isr();}
	if (list[7] && TimerCHInPending(&IMXRT_TMR3.CH[3])) { list[7]->isr();}
	if (list[8] && TimerCHInPending(&IMXRT_TMR3.CH[1])) { list[8]->isr();}
	if (list[9] && TimerCHInPending(&IMXRT_TMR3.CH[0])) { list[9]->isr();}
	asm volatile ("dsb");  // wait for clear  memory barrier
	digitalWriteFast(2, LOW);
}
Hooked up USB to serial adapter to pin 1, and did a Serial1.begin in setup...
Now seeing:
Code:
isrTimer3: 0 0 0 200013d0
     0: 1d40 0300 1: a10b 1311 2: a10b 1311 3: a00b 1311
isrTimer3: 0 0 0 200013d0
     0: 9c40 0310 1: a00b 1311 2: a00b 1311 3: a00b 1311
isrTimer3: 0 0 0 200013d0
     0: 9c40 0310 1: a00b 1311 2: a00b 1311 3: a00b 1311
isrTimer3: 0 0 0 200013d0
     0: 9c40 0310 1: a00b 1311 2: a00b 1311 3: a00b 1311
isrTimer3: 0 0 0 200013d0
     0: 9c40 0310 1: a00b 1311 2: a00b 1311 3: a00b 1311
isrTimer3: 0 0 0 200013d0
     0: 9c40 0310 1: a00b 1311 2: a00b 1311 3: a00b 1311
isrTimer3: 0 0 0 200013d0
     0: 9c40 0310 1: a00b 1311 2: a00b 1311 3: a00b 1311
isrTimer3: 0 0 0 200013d0
     0: 9c40 0310 1: a00b 1311 2: a00b 1311 3: a00b 1311
isrTimer3: 0 0 0 200013d0
     0: 9c40 0310 1: a00b 1311 2: a00b 1311 3: a00b 1311
isrTimer3: 0 0 0 2000

And now debugging: So it shows I have list[9] with object as expected. Now
To look at the SCTRL and CSCTRL values to see which channel is actually triggering the ISR...
For CH:0 we have
SCTRL: 9c40 TCF, TOFIE, IEF IEFIE, CAPTURE_MODE(1)
CSCTRL: 0310 UP, TCF1

So I think it should trigger the input ISR?

Oops found it. :eek:

Look at the function:
Code:
inline bool TimerCHInPending(volatile IMXRT_TMR_CH_t *tmr_ch) {
 	if ((tmr_ch->CSCTRL & (TMR_CSCTRL_TCF1 | TMR_CSCTRL_TCF1EN)) == (TMR_CSCTRL_TCF1 | TMR_CSCTRL_TCF1EN)) 
 		return true;
 	if ((tmr_ch->SCTRL & (TMR_SCTRL_TOF | TMR_SCTRL_TOFIE)) == (TMR_SCTRL_TOF | TMR_SCTRL_TOFIE)) 
 		return true;
	if (([COLOR="#FF0000"]IMXRT_TMR1.CH[2].[/COLOR]SCTRL & (TMR_SCTRL_IEF | TMR_SCTRL_IEFIE)) == (TMR_SCTRL_IEF | TMR_SCTRL_IEFIE))
		return true;
	return false;
}
Should be:
Code:
inline bool TimerCHInPending(volatile IMXRT_TMR_CH_t *tmr_ch) {
 	if ((tmr_ch->CSCTRL & (TMR_CSCTRL_TCF1 | TMR_CSCTRL_TCF1EN)) == (TMR_CSCTRL_TCF1 | TMR_CSCTRL_TCF1EN)) 
 		return true;
 	if ((tmr_ch->SCTRL & (TMR_SCTRL_TOF | TMR_SCTRL_TOFIE)) == (TMR_SCTRL_TOF | TMR_SCTRL_TOFIE)) 
 		return true;
	if ((tmr_ch->SCTRL & (TMR_SCTRL_IEF | TMR_SCTRL_IEFIE)) == (TMR_SCTRL_IEF | TMR_SCTRL_IEFIE))
		return true;
	return false;
}
 
@KurtE
;)

If you are going to test pin 19 make sure you add: IOMUXC_QTIMER3_TIMER0_SELECT_INPUT = 0x02; //pin 19 to the begin.

I just tried - no more hangs but no data showing up either. It is getting to the ISR but don't have as many debug statements in yet.
 
@mjs513, Here is my latest stuff, which is working I think on pin 19. You may have the wrong mux value.

The Mux register/value was added to my hardware table.

I also made the digitalWriteFast stuff, to be able to turn on or off with #define at top, likewise debug serial prints.

Forgot to mention, I switched back to using match instead of overflow. I could/should remove the test looking for it, ...

Here is the run with it using pin pin
Code:
2(20001):  750.05  1500.05  2250.08  
3(20000):  750.05  1500.05  2250.08  
4(20001):  750.05  1500.05  2250.08  
5(20000):  750.05  1500.05  2250.08  
6(20001):  750.05  1500.05  2250.08

Which is matching pretty well my 750, 1500, 2250 I passed in to output...
 

Attachments

  • PulsePosition_t4.zip
    7.1 KB · Views: 151
I am trying out several of the IO pins to see if they work for input: Currently driving by pin 9, will reviers to see.
Working: 6, 10, 11, 12, 13, 14, 15, 19
Not Working: 18, need to double check MUX setting.
9 Works with 19 output

18 Fixed (MUX 0 not 1) - I commented out test for overflow...
 

Attachments

  • PulsePosition_t4.zip
    7.1 KB · Views: 150
If I were going to make another pass in this, one thing I would double check is we set the list table value to this, before we enable interrupts as to make sure we have it set before any possible time the ISRs are called... Also I might add in a little robustness.

My thoughts are currently have it like:
Code:
void PulsePositionBase::isrTimer1()
{
	DBGdigitalWriteFast(2, HIGH);
	if (list[2] && TimerCHInPending(&IMXRT_TMR1.CH[0])) { list[2]->isr();}
	if (list[3] && TimerCHInPending(&IMXRT_TMR1.CH[2])) { list[3]->isr();}
	if (list[4] && TimerCHInPending(&IMXRT_TMR1.CH[1])) { list[4]->isr();}
	asm volatile ("dsb");  // wait for clear  memory barrier
	DBGdigitalWriteFast(2, LOW);
}

But am thinking to make TimerCHInPending be a member function of base (probably inline), maybe called more like:
processTimerCHInPending and pass in the list item number like:
My thoughts are currently have it like:
Code:
void PulsePositionBase::isrTimer1()
{
	DBGdigitalWriteFast(2, HIGH);
	processTimerCHInPending(2, &IMXRT_TMR1.CH[0]);
	processTimerCHInPending(3, &IMXRT_TMR1.CH[2]);
	processTimerCHInPending(4, &IMXRT_TMR1.CH[1]);
	asm volatile ("dsb");  // wait for clear  memory barrier
	DBGdigitalWriteFast(2, LOW);
}
Where the process function, would do sort like the helper function does now, and IF it thinks there is an active interrupt pending on that channel, it would then check to see if list[n] is set and call it, else it would clear out those interrupt bits, as to not get called again and hang...

Make sense. I will be off for awhile, so if someone beats me to it...

Kurt

EDIT: Done:
 

Attachments

  • PulsePosition_t4.zip
    7 KB · Views: 112
Last edited:
I was never able to get overflow (TOF) interrupt to work on T4 quad timer, so I used timer compare (0xffff) to count timer overflows.
Just for the record, NXP discussion confirms bug in quad timer overflow interrupt -- though it does fire if counting down. Should be documented in latest errata.
 
@KurtE

Wow - I just back on the computer and its all done :)

Just did a couple of tests. (1) using 2 T4's all pins are receiving and transmitting (only tested 3 really)… The receive pins are receiving the correct data and match the format that we would expect from a T3.x

The second test was more fun. Loopback using 3 output pins and 3 receive pins. Bottom line SUCCESS - you solved the puzzle!
Code:
1941 :  600.08  1500.05  759.28  1500.05  1500.05  1234.61  
1942 :  634.59  
1942 :  2234.64  1500.05  1029.23  
1942 :  600.08  1500.05  759.28  1500.05  1500.05  1234.61  
1943 :  634.59  
1943 :  2234.64  1500.05  1029.23  
1943 :  600.08  1500.05  759.28  1500.05  1500.05  1234.61  
1944 :  634.59  
1944 :  2234.64  1500.05  1029.23  
1944 :  600.08  1500.05  759.28  1500.05  1500.05  1234.61

Heres the sketch if you want to play:
Code:
#include <PulsePosition_t4.h>

PulsePositionInput myIn;
PulsePositionOutput myOut;
PulsePositionOutput myOut1;
PulsePositionOutput myOut2;
PulsePositionInput myIn1;
PulsePositionInput myIn2;

void setup() {
  myIn.begin(19);
  myIn1.begin(18);
  myIn2.begin(15);
  
  Serial.begin(115200);
  delay(2000);
  myOut.begin(13);
  myOut1.begin(6);
  myOut2.begin(11);

  myOut.write(1, 600.03);
  myOut.write(2, 1500);
  myOut.write(3, 759.24);
  // slots 4 and 5 will default to 1500 us
  myOut.write(6, 1234.56);
  myOut1.write(1, 2234.56);
  myOut1.write(3, 1029.19);
  myOut2.write(1, 634.56);

}

void loop() {
  int i, num;
  static int count = 0;
  int i1, num1;
  static int count1 = 0;
   int i2, num2;
  static int count2 = 0;

  
  // Every time new data arrives, simply print it
  // to the Arduino Serial Monitor.
  num = myIn.available();
  if (num > 0) {
    count = count + 1;
    Serial.print(count);
    Serial.print(" :  ");
    for (i=1; i <= num; i++) {
      float val = myIn.read(i);
      Serial.print(val);
      Serial.print("  ");
    }
    Serial.println();
  }

  num1 = myIn1.available();
  if (num1 > 0) {
    count1 = count1 + 1;
    Serial.print(count1);
    Serial.print(" :  ");
    for (i=1; i <= num1; i++) {
      float val1 = myIn1.read(i);
      Serial.print(val1);
      Serial.print("  ");
    }
    Serial.println();
  }

  num2 = myIn2.available();
  if (num1 > 0) {
    count2 = count2 + 1;
    Serial.print(count2);
    Serial.print(" :  ");
    for (i=1; i <= num2; i++) {
      float val2 = myIn2.read(i);
      Serial.print(val2);
      Serial.print("  ");
    }
    Serial.println();
  }
}

So which way do we want to go now - merge this pulse position or keep a separate T4 library?
 
Just for the record, NXP discussion confirms bug in quad timer overflow interrupt -- though it does fire if counting down. Should be documented in latest errata.

Well that's 2 major things that are errors within the 1060! This and flexcan-FD FIFO.

At least we know it wasn't something we all were doing wrong.
 
So which way do we want to go now - merge this pulse position or keep a separate T4 library?

If it were me, I think I would do a half combine ;)

That is, I think I might do something like:

Actually in both cases, would tend to do all of the normal library header stuff like in both header files.

#ifndef __PULSE_POSITION_IN_H__
#define __PULSE_POSITION_IN_H__
.....
#endif

I would then edit PulsePosition.h file and maybe start off with something like:

Code:
#ifdef __AVR__
#error "Sorry, PulsePosition does not work on Teensy 2.0 and other AVR-based boards"
#elif defined(__IMXRT1062__)
#include "PulsePosition_t4.h"
#else 
..... all current stuff 

#endif
And then in PulsePositioin_t4.h and .cpp bracket the whole file with:
Code:
#if defined(__IMXRT1062__)
.....
#endif

This is sort of what Paul did in wire library, where there are files split off WireKinetis and WireIMXRT

Edit: Actually maybe the files should be renamed like: PulsePositionIMXRT.h like wire...
 
@KurtE
Will go the route u suggest, better that way.

Have a couple more tests to run
(1) frame pin and
(2).rising and falling for polarity

Know polarity works for tx cause I had a scope on the pins this morning, early morning.
 
@KurtE - @manitou ….

Just finished testing. Had a slight bug for implementing framePin but all is good now. Want to change digitalWrites to digitalWriteFast for final version.

Also I just noted that when input is set to RISING or FALLING it doesn't matter to output capture. Will capture either on rising or falling edge.....
 
@mjs513 @KurtE
Using your latest zip from this thread, I ran various tests with T4 loopback and data from T3.2 PulsePosition. All looks good. Impressive work managing all the ISRs!!

Re: down counting and overflow interrupt
As noted, though the quad timer overflow interrupt does NOT work when counting up, it does fire when counting down (DIR). FWIW, I made another version of my ppminq.ino sketch to count down and use the TOF interrupt rather than compare interrupt. Also complemented saved capture value so the saved values are counting up. Here is summary of changes for PPM Input
Code:
Change to initialize overflow interrupt instead of compare
>   [B][COLOR="#0000CD"]TMR1_SCTRL2 |= TMR_SCTRL_TOFIE;[/COLOR][/B]  // enable oflow interrupt

change start up config to down count and no LENGTH
>   [B][COLOR="#0000CD"]TMR1_CTRL2 =  TMR_CTRL_DIR | TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | TMR_CTRL_SCS(2);[/COLOR][/B] // prescale

In isr replace compare logic with overflow logic
> void my_isr() {  // capture and underflow
>  [B][COLOR="#0000CD"] if (TMR1_SCTRL2 & TMR_SCTRL_TOF)[/COLOR][/B] { // underflow rollover
>     [B][COLOR="#0000CD"][COLOR="#0000CD"]TMR1_SCTRL2 &= ~(TMR_SCTRL_TOF);[/COLOR][/COLOR][/B]  // clear

and in isr, flip bits when saving captured value
>     [B][COLOR="#0000CD"]val = (uint16_t)~(TMR1_CAPT2);[/COLOR][/B]   // count up

I don't know if using the overflow interrupt rather than the compare interrupt would have simplified your ISR management.
 
Last edited:
Hi @mjs513 and others... Good morning. Great stuff.

Wondering if it would be a good idea to update the Readme.md file as part of this... Still back in the ice age that only mentions Teensy 3.1

I did a quick and dirty update which is up in my branch: https://github.com/KurtE/PulsePosition/tree/readme

Which has the contents:
Code:
PulsePosition
=============

Multiple High-Res Input & Output PPM Encoded Signal Streams on Teensy 3.x, LC, and 4.0

Valid pins (input or output) by board type:
```
Teensy 3.6, 3.5:  5, 6, 9, 10, 20, 21, 22, 23
Teensy 3.2, 3.1:  5, 6, 9, 10, 20, 21, 22, 23
Teensy LC:        6, 9, 10, 20, 22, 23
Teensy 4.0:       6, 9, 10, 11, 12, 13, 14, 15, 18, 19
```
http://www.pjrc.com/teensy/td_libs_PulsePosition.html

Could potentially add additional information.
@Paul: Also note: The referred to html file needs updates as well to mention 4.0 and (8 pins versus 10...)
 
@KurtE - @manitou

@KurtE - I went ahead and updated the Readme with the added info to match what you have in your readme which is a good idea.

@manitou - very cool that you got down counting and overflow interrupt working.

@Paul - besides PulsePosition you are gong to have to update FreqMeas lib as well to show that pin 9 is used for input.
 
Status
Not open for further replies.
Back
Top