PDA

View Full Version : Teensyduino 1.48 Beta #3



Paul
10-06-2019, 12:21 PM
Here is a third beta test for Teensyduino 1.48.


Linux 32 bit:
https://www.pjrc.com/teensy/td_148-beta3/TeensyduinoInstall.linux32

Linux 64 bit:
https://www.pjrc.com/teensy/td_148-beta3/TeensyduinoInstall.linux64

Linux ARM:
https://www.pjrc.com/teensy/td_148-beta3/TeensyduinoInstall.linuxarm

Linux ARM64:
https://www.pjrc.com/teensy/td_148-beta3/TeensyduinoInstall.linuxaarch64

Mac OS-X:
https://www.pjrc.com/teensy/td_148-beta3/TeensyduinoInstall.dmg

Windows:
https://www.pjrc.com/teensy/td_148-beta3/TeensyduinoInstall.exe


Changes since Teensyduino 1.48-beta2 (https://forum.pjrc.com/threads/57872-Teensyduino-1-48-Beta-2)

Add CPU Speed menu for Teensy 4.0
Fix SoftwareSerial on Teensy 4.0 (KurtE)
Fix Wire on Teensy 4.0 when I2C device prior NAK (KurtE)
Add startup hooks on Teensy 4.0 (Defragster)
Fix Audio TDM & I2C2 on Teensy 4.0
Improve Audio I/O on overclocked Teensy 3.6
Fix ST7735_t3 DMA (KurtE)
Update TeensyThreads

PaulStoffregen
10-06-2019, 12:32 PM
My hope is to release 1.48 soon, probably very close to this 3rd beta.

The serial monitor timestamp feature still missing. Sorry, it just isn't going to happen for 1.48, since the speedup stuff bypasses that part of the serial monitor's abstraction layers. :(

After we have a stable 1.48 release, I'm going to start work again on the missing USB types and porting the remaining Teensy3-only libraries like OctoWS2811.

mjs513
10-06-2019, 02:51 PM
Morning all

Downloaded and install on a Windows10x64 with no issues during the install.

Can copy from a closed sermon of course.

Tried the demosauce sketch that identified the issue hang with the PIT timer in startup and that worked now without issue.

Changed clock speed from 600Mhz to 816Mhz and that work - tested with one of the ILI9341 test sketches. Ok - tested up to 1Ghz.(no cooling)
1. at 1Ghz - lost usb on upload probably max temp shutdown
2. at 960 T4 kept resetting - probably max temp reached
3. at 912 T4 ran a few seconds then lost usb but sketch kept running.

manitou
10-06-2019, 06:20 PM
My hope is to release 1.48 soon, probably very close to this 3rd beta.

The serial monitor timestamp feature still missing. Sorry, it just isn't going to happen for 1.48, since the speedup stuff bypasses that part of the serial monitor's abstraction layers. :(

After we have a stable 1.48 release, I'm going to start work again on the missing USB types and porting the remaining Teensy3-only libraries like OctoWS2811.

Any thoughts on WDOG reset not working on T4 (1060) but did work on T4B1 (1050)? Discussed in
https://forum.pjrc.com/threads/54711-Teensy-4-0-First-Beta-Test?p=217661&viewfull=1#post217661
and
https://forum.pjrc.com/threads/57810-Soft-reboot-on-Teensy4-0

defragster
10-06-2019, 06:28 PM
Downloaded but not yet installed B_3. I see MAX voltage updated to hardware spec for OC.


...
Changed clock speed from 600Mhz to 816Mhz and that work - tested with one of the ILI9341 test sketches. Ok - tested up to 1Ghz.(no cooling)
1. at 1Ghz - lost usb on upload probably max temp shutdown
2. at 960 T4 kept resetting - probably max temp reached
3. at 912 T4 ran a few seconds then lost usb but sketch kept running.

With added startup hook - a serial# port could be made active to push out TempMon data before setup.

Paul posted the TWO benchmarks - last I ran them both ran at 700 but only one at 800 MHz - would be interesting to see results with new higher MAX V on more than one unit.

KurtE
10-06-2019, 07:15 PM
Beta 3 installed W10 1.8.10 so far so good.

defragster
10-06-2019, 07:43 PM
1.8.10 w/ TD 1.48 B3 installed - with PORTABLE dir in place so it came up using that subset directory. Funny just noticed it was not doing VERBOSE compile as that was unset in current Portable.

No problem - looks good for WIN 10

I removed the sketchbook\libraries\TeensyThreads and the now updated included version work to run the USBHost LAN Ethernet build!

TeensyThreads is giving this minor warning {it was before too}:


T:\arduino_1.8.10\hardware\teensy\avr\libraries\Te ensyThreads\TeensyThreads.cpp:327:13: warning: 'void context_pit_empty()' defined but not used [-Wunused-function]
static void context_pit_empty() {}



Multiple libraries were found for "TeensyThreads.h"
Used: T:\arduino_1.8.10\hardware\teensy\avr\libraries\Te ensyThreads
Multiple libraries were found for "fnet.h"
Used: T:\arduino_1.8.10\portable\sketchbook\libraries\FN ET
Multiple libraries were found for "USBHost_t36.h"
Used: T:\arduino_1.8.10\hardware\teensy\avr\libraries\US BHost_t36
Multiple libraries were found for "ASIXEthernet.h"
Used: T:\arduino_1.8.10\portable\sketchbook\libraries\Te ensyASIXEthernet
Using library USBHost_t36 at version 0.1 in folder: T:\arduino_1.8.10\hardware\teensy\avr\libraries\US BHost_t36
Using library TeensyASIXEthernet in folder: T:\arduino_1.8.10\portable\sketchbook\libraries\Te ensyASIXEthernet (legacy)
Using library TeensyThreads at version 1.0.1 in folder: T:\arduino_1.8.10\hardware\teensy\avr\libraries\Te ensyThreads
Using library FNET at version 0.1.2 in folder: T:\arduino_1.8.10\portable\sketchbook\libraries\FN ET

mjs513
10-06-2019, 07:58 PM
Downloaded but not yet installed B_3. I see MAX voltage updated to hardware spec for OC.



With added startup hook - a serial# port could be made active to push out TempMon data before setup.

Paul posted the TWO benchmarks - last I ran them both ran at 700 but only one at 800 MHz - would be interesting to see results with new higher MAX V on more than one unit.

Just ran the Coremark up through 1Ghz, no problems. Was running Demosauce so a heavier load:
17827

Believe @manitou also ran coremarks

PaulStoffregen
10-06-2019, 08:08 PM
The multiple libraries warning when only a single library exists is (probably) a bug in arduino-builder.exe. That's not going to be fixed by 1.48, since we currently do not patch arduino-builder in any way.

defragster
10-06-2019, 08:21 PM
@Paul - Portable works for install and afterward without Portable. The SPEED menu works { good now I can remove the HACK to TSET and use external editor and TyComm! }. And at least at 600 and 816 MHz the T_4 spped to run well with the MAX voltage update.

Exited 'Portable' - renamed 'Portable' to 'xPortable' - restart IDE in the system based prior config - all prior sketches opened.

As above removed sketchbook\libraries\TeensyThreads and built USBHost LAN code - running Teensy 4.0 at 816MHz - does not result in change to test throughput { PC LAN to USBHost LAN is at 30 Kbits/sec or ~27 ms for 102,400 Bytes in 20 transfers } - but it does run.

NOTE: At 816 MHz loop()/second is 10,276,692 under TeensyThreads where 2nd thread handles USB/LAN and dropping back to 600 MHz the loop()/sec count is 7,509,250

Seeing ~8900 high speed pings in 10 seconds with MSFT PSPING64 { same at 600 and 816 MHz : ALSO same on T_3.6 at 256 MHz }:


T:\T_Downloads\PSTools>psping64.exe -i 0 -q -n 10s 192.168.0.23

PsPing v2.10 - PsPing - ping, latency, bandwidth measurement utility
Copyright (C) 2012-2016 Mark Russinovich
Sysinternals - www.sysinternals.com

Pinging 192.168.0.23 with 32 bytes of data:
10 seconds (1 warmup pings) connecting test: 100%

Ping statistics for 192.168.0.23:
Sent = 8993, Received = 8993, Lost = 0 (0% loss),
Minimum = 0.31ms, Maximum = 6.69ms, Average = 0.89ms

BOTH of these now run at 600 and 816 MHz - one of them before failed at 800 MHz - before the Max Voltage bump.

Coremark at 600 MHZ: Iterations/Sec : 2313.57
Coremark at 816 MHZ: Iterations/Sec : 3146.39



600 MHz :: RSA Signature Speed Test Signature computation took 0.085 seconds
816 MHz :: RSA Signature Speed Test Signature computation took 0.063 seconds


Didn't test TempMon with speed change or re-run the StartupHooks test yet ...

defragster
10-06-2019, 08:23 PM
The multiple libraries warning when only a single library exists is (probably) a bug in arduino-builder.exe. That's not going to be fixed by 1.48, since we currently do not patch arduino-builder in any way.

Good to know you saw it - will wait for fix.

Hacky
10-06-2019, 08:24 PM
Thanks for the update, Paul. Did you have a chance to look why the PulsePlosition library coming with TD does not compile anymore with T4?
(see also https://forum.pjrc.com/threads/57872-Teensyduino-1-48-Beta-2?p=217887&viewfull=1#post217887)

PaulStoffregen
10-06-2019, 08:39 PM
Did you have a chance to look why the PulsePlosition library coming with TD does not compile anymore with T4?

PulsePosition hasn't been ported yet. It's filled with FTM/TPM timer code. Only Teensy 3.x & LC have those timers. NXP put different timers in this IMXRT new chip.

I will eventually port PulsePosition, maybe to the FlexPWM timers, maybe to the quad timers. But that's not going to happen for the 1.48 release.

PaulStoffregen
10-06-2019, 11:27 PM
Any thoughts on WDOG reset not working on T4 (1060) but did work on T4B1 (1050)?

Not sure. I tried several different software reset ways. All fail and I don't know why.

Not going to hold up the 1.48 release for this. But I have put it on my list of bugs to investigate.

defragster
10-07-2019, 12:15 AM
@Paul - check speed text in boards.txt.

Selecting :: teensy40.menu.speed.1008=1.008 GHz (overclock, cooling req'd)
Uses :: teensy40.menu.speed.1008.build.fcpu=1000000000

Starts with F_CPU_ACTUAL :: F_CPU=996000000

Changing to this works:: teensy40.menu.speed.1008.build.fcpu=1008000000

F_CPU=1008000000


FYI: Paul when the 1062 goes offline from OC'ing F_CPU Windows Consoles shows things like this - the last line came on button press:


Unable to open COM39 for reboot request
Windows Error Info: Access is denied.
more ideas... https://forum.pjrc.com/threads/40632?p=126667&viewfull=1#post126667
Teensy did not respond to a USB-based request to enter program mode.
Please press the PROGRAM MODE BUTTON on your Teensy to upload your sketch.
Unable to open COM39
Now able to open COM39 (Windows said this port was ready before it was actually ready...)Disconnect COM39

This T_4 is on the TallDog beta breakout - so some heat can dissipate and runs okay for simple temp mon test at 960 MHz.

@mjs513 - this sketch has startup hooks coded and attempts to grab the TempMon ISR's?


17831


I didn't hook up Serial1 or other UART printing for when USB goes offline - but not sure the temp is going HIGH and halting gracefully? prints temps and unless it crashes fast once it hits a 60 tipping point it seems to not be catching the TempMon code for any notice or pBlink calls?

mjs513
10-07-2019, 12:23 AM
Not sure. I tried several different software reset ways. All fail and I don't know why.

Not going to hold up the 1.48 release for this. But I have put it on my list of bugs to investigate.

@PaulStoffregen

This seems to be the same issue associated with SCB_AIRCR not resetting the T4. Its like the T4 appears to turn-off instead of resetting. If you reapply power it turns back on.

mjs513
10-07-2019, 12:34 AM
@mjs513 - this sketch has startup hooks coded and attempts to grab the TempMon ISR's?

TempMonTest.ino
I didn't hook up Serial1 or other UART printing for when USB goes offline - but not sure the temp is going HIGH and halting gracefully? prints temps and unless it crashes fast once it hits a 60 tipping point it seems to not be catching the TempMon code for any notice or pBlink calls

@defragster

Thanks for moding the example. When I ran coremark up to 1.008Ghz(1ghz) it ran without issue. When I ran demosauce that was when things started happening with resetting and loosing USB

defragster
10-07-2019, 12:44 AM
@defragster

Thanks for moding the example. When I ran coremark up to 1.008Ghz(1ghz) it ran without issue. When I ran demosauce that was when things started happening with resetting and loosing USB

Note above - requesting 1008 actually runs at 996. I am finding that TempMonTest.ino will go offline about always at 1008 ( 996 or 1008 with edit ) - and prints go funny at 960 with a couple garb chars showing - and sometime it just vanishes on USB with no special blinky lights as expected. Thought you might check the code - not sure it is getting as far as seeing PANIC temp of 95C before failure. Originally I was testing that with lower threshold temps in TempMon - but that was weeks back and that code is gone now

mjs513
10-07-2019, 01:10 AM
Note above - requesting 1008 actually runs at 996. I am finding that TempMonTest.ino will go offline about always at 1008 ( 996 or 1008 with edit ) - and prints go funny at 960 with a couple garb chars showing - and sometime it just vanishes on USB with no special blinky lights as expected. Thought you might check the code - not sure it is getting as far as seeing PANIC temp of 95C before failure. Originally I was testing that with lower threshold temps in TempMon - but that was weeks back and that code is gone now

I'll check it out - you guys are night owls while I am a morning person - so give me a little bit. Still have my original sketch where I can adjust the temps. If I remember right it is currently set for 90degC - may have to change the temp alarms for testing :)

defragster
10-07-2019, 01:13 AM
Right 90 - recalled 95 last look - but that was wrong ...


static uint16_t frequency = 0x03U;
static uint32_t highAlarmTemp = 85U;
static uint32_t lowAlarmTemp = 25U;
static uint32_t panicAlarmTemp = 90U;

Posted sketch had them extern'd IIRC to edits in TempMon … some time back ...

mjs513
10-07-2019, 01:46 AM
Right 90 - recalled 95 last look - but that was wrong ...



Posted sketch had them extern'd IIRC to edits in TempMon … some time back ... Have to find the original doc I used to set 90 may be able to raised to 95.

PaulStoffregen
10-07-2019, 02:43 AM
Selecting :: teensy40.menu.speed.1008=1.008 GHz (overclock, cooling req'd)
Uses :: teensy40.menu.speed.1008.build.fcpu=1000000000


Oh, opps, I missed editing that number. Already something to fix for 1.49...

As far as trying other overclocking, just editing those numbers in boards.txt lets you try pretty much any frequency. The PLL can generate up to 1.296 GHz. But the DCDC converter is limited to 1.575 volts and it's already at that maximum with 1 GHz. How much faster the CPU can really run will only depend on cooling.

If anyone has a *lot* of time to try overclocking, I'd love to hear some feedback about whether the rate set_arm_clock() increases voltage with frequency is good. I'll admit, this line was pretty much just a guess on my part based on only a couple quick trials, and on the early 1052 beta boards.


#define OVERCLOCK_STEPSIZE 28000000

This number means set_arm_clock() will increase the voltage by a 0.025V step for every 28 MHz over the 600 MHz. How much voltage should really be used is just a matter of experimentation. NXP's datasheet gives no guidance, other than 1.3V is the maximum recommended and we're supposed to use 0.95V for 24 MHz, 1.15V for 25-528 MHz, and 1.25V for 529-600 MHz.

Maziac
10-12-2019, 11:27 AM
I updated to Catalina and did a fresh install of Arduino 1.8.10.
I started Arduino, gave it full access rights to all drives and **was able to compile a sketch**.

Then I executed the Teensyduino.app 1.48-beta3.
After it finished I ran Arduino, set the board to TeensyLC and chose an USB Type.
Then run "Verify" (e.g. Blink sketch) and get an error.



Arduino: 1.8.10 (Mac OS X), TD: 1.48-beta3, Board: "Teensy LC, Serial + Keyboard + Mouse + Joystick, 48 MHz, Smallest Code, US English"

/Volumes/SDDPCIE2TB/Applications/Arduino.app/Contents/Java/arduino-builder -dump-prefs -logger=machine -hardware /Volumes/SDDPCIE2TB/Applications/Arduino.app/Contents/Java/hardware -hardware /Users/bob/Library/Arduino15/packages -tools /Volumes/SDDPCIE2TB/Applications/Arduino.app/Contents/Java/tools-builder -tools /Volumes/SDDPCIE2TB/Applications/Arduino.app/Contents/Java/hardware/tools/avr -tools /Users/bob/Library/Arduino15/packages -built-in-libraries /Volumes/SDDPCIE2TB/Applications/Arduino.app/Contents/Java/libraries -libraries /Users/bob/Documents/Arduino/libraries -fqbn=teensy:avr:teensyLC:usb=serialhid,speed=48,op t=osstd,keys=en-us -ide-version=10810 -build-path /var/folders/gr/817lnxns137006z93d2dz7b00000gn/T/arduino_build_819008 -warnings=none -build-cache /var/folders/gr/817lnxns137006z93d2dz7b00000gn/T/arduino_cache_290583 -verbose /var/folders/gr/817lnxns137006z93d2dz7b00000gn/T/untitled1941406174.tmp/sketch_oct12a/sketch_oct12a.ino
loading libs from /Users/bob/Documents/Arduino/libraries: reading dir /Users/bob/Documents/Arduino/libraries: open /Users/bob/Documents/Arduino/libraries: operation not permitted

Error compiling for board Teensy LC.


Then I changed board back to Uno but also the same:



Arduino: 1.8.10 (Mac OS X), TD: 1.48-beta3, Board: "Arduino/Genuino Uno"

/Volumes/SDDPCIE2TB/Applications/Arduino.app/Contents/Java/arduino-builder -dump-prefs -logger=machine -hardware /Volumes/SDDPCIE2TB/Applications/Arduino.app/Contents/Java/hardware -hardware /Users/bob/Library/Arduino15/packages -tools /Volumes/SDDPCIE2TB/Applications/Arduino.app/Contents/Java/tools-builder -tools /Volumes/SDDPCIE2TB/Applications/Arduino.app/Contents/Java/hardware/tools/avr -tools /Users/bob/Library/Arduino15/packages -built-in-libraries /Volumes/SDDPCIE2TB/Applications/Arduino.app/Contents/Java/libraries -libraries /Users/bob/Documents/Arduino/libraries -fqbn=arduino:avr:uno -ide-version=10810 -build-path /var/folders/gr/817lnxns137006z93d2dz7b00000gn/T/arduino_build_819008 -warnings=none -build-cache /var/folders/gr/817lnxns137006z93d2dz7b00000gn/T/arduino_cache_290583 -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.avrdude.path=/Users/bob/Library/Arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17 -prefs=runtime.tools.avrdude-6.3.0-arduino17.path=/Users/bob/Library/Arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17 -prefs=runtime.tools.arduinoOTA.path=/Users/bob/Library/Arduino15/packages/arduino/tools/arduinoOTA/1.3.0 -prefs=runtime.tools.arduinoOTA-1.3.0.path=/Users/bob/Library/Arduino15/packages/arduino/tools/arduinoOTA/1.3.0 -prefs=runtime.tools.avr-gcc.path=/Users/bob/Library/Arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino5 -prefs=runtime.tools.avr-gcc-7.3.0-atmel3.6.1-arduino5.path=/Users/bob/Library/Arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino5 -verbose /var/folders/gr/817lnxns137006z93d2dz7b00000gn/T/untitled1941406174.tmp/sketch_oct12a/sketch_oct12a.ino
loading libs from /Users/bob/Documents/Arduino/libraries: reading dir /Users/bob/Documents/Arduino/libraries: open /Users/bob/Documents/Arduino/libraries: operation not permitted

Error compiling for board Arduino/Genuino Uno.


I.e. after executing Teensyduino.app the Arduino.app does not work anymore.

Any idea.
Maybe a problem with the access rights? But as stated above: I gave Arduino full access to the hard disks.

Not sure if this if of importance: I installed Arduino.app not in the usual /Applications directory but on an external hard disk /Volumes/exthd/Applications/Arduino.app.

Theremingenieur
10-12-2019, 02:50 PM
Running already macOS Catalina 15.1 beta here since last night. Fresh install of Arduino 1.8.10, granted rights, the installed Teensyduino 1.48 final release, not beta. Launches, loads sketches, compiles, and uploads without problems.

Maziac
10-12-2019, 04:40 PM
It's working now for me as well.

Maybe this helps someone:
To get it to work I had to remove the complete "Arduino" folder under home Documents.
Then I reinstalled the libraries.

I guess this had something to do with the access rights.

manitou
10-23-2019, 09:15 PM
PulsePosition hasn't been ported yet. It's filled with FTM/TPM timer code. Only Teensy 3.x & LC have those timers. NXP put different timers in this IMXRT new chip.

I will eventually port PulsePosition, maybe to the FlexPWM timers, maybe to the quad timers. But that's not going to happen for the 1.48 release.

I have a proof of concept sketch for PPM input portion of PulsePosition for the T4 using quad timer, see
https://github.com/manitou48/teensy4/blob/master/ppminq.ino
This was based on earlier sketch/discussion (https://forum.pjrc.com/threads/54711-Teensy-4-0-First-Beta-Test?p=199536&viewfull=1#post199536) that used T4 quad timer. As with that sketch, 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. In the ppminq.ino sketch the T4 quad timer is clocked at 37.5 MHz. I tested with a T3.2 running PulsePosition LoopBack example with PPM output on T3.2 pin 9 jumpered to T4 capture pin 11. The printed output looks good.

1086 : 600.03 1500.03 759.23 1500.03 1500.00 1234.56
1087 : 600.03 1500.00 759.25 1500.00 1500.03 1234.53
1088 : 600.03 1500.03 759.23 1500.03 1500.00 1234.56
1089 : 600.03 1500.00 759.25 1500.00 1500.03 1234.53
You can flip polarity with TMR_SCTRL_IPS.

Now to see how to get the T4 to generate PPM out pulses...

manitou
10-24-2019, 09:05 PM
I have a proof of concept sketch for PPM input portion of PulsePosition for the T4 using quad timer, see
https://github.com/manitou48/teensy4/blob/master/ppminq.ino

Now to see how to get the T4 to generate PPM out pulses...

Here is a T4 quadtimer sketch that emits PPM pulses like the example in PulsePosition lib.
https://github.com/manitou48/teensy4/blob/master/ppmoutq.ino
Much of the logic is lifted from PulsePostion lib. Polarity can be changed with TMR_SCTRL_OPS. I verified with scope and jumpered T4 PPM output to T3.2 running PulsePostion lib LoopBack example. Here is the output from T3.2

21538 : 600.08 1500.04 759.27 1500.04 1500.04 1234.60
21539 : 600.08 1500.04 759.27 1500.04 1500.04 1234.60
21540 : 600.08 1500.04 759.27 1500.04 1500.04 1234.60
21541 : 600.08 1500.04 759.27 1500.04 1500.04 1234.60

manitou
10-25-2019, 11:13 AM
Sketch in previous post is working now with T3.2 PulsePosition example. I updated github. I'll let others test and weave logic in to PulsePosition lib ...

mjs513
10-25-2019, 12:14 PM
@manitou
Nice. I just put your input sketch on one T4 and the output on another T4. Jumped pins 10 (output) to pin 11 (input) and got:

201 : 600.08 1500.05 759.28 1500.03 1500.05 1234.61
202 : 600.08 1500.05 759.28 1500.03 1500.05 1234.61
203 : 600.08 1500.05 759.25 1500.05 1500.05 1234.61
204 : 600.08 1500.03 759.28 1500.05 1500.05 1234.61
205 : 600.08 1500.03 759.28 1500.05 1500.05 1234.61
Out of curiosity I hooked up a scope to the output and wanted to see what happened when I reversed polarity. Yep and it worked, polarity was reversed as advertised.

Have to read up on PPM signals a bit then guess I will give it a go to update the lib unless someone beats me to it. That weaving you mentioned will probably confuse me but that's nothing new.

manitou
10-25-2019, 01:19 PM
Excellent. There are 10 quadtimer pins on T4. One problem requiring additional logic with both quadtimer PPM out and in in the same lib is that I never could get quadtimer Overflow interrupt to work (??). Counter in overflow interrupt is used to generate 32-bit counter for capture values. I had to use compare-value interrupt (0xffff) to count overflows, BUT compare-value interrupt is used in PPM out. So you'd need to know which pin is in capture mode and which pin is in compare mode to follow the proper path in the ISR -- maybe just look at timer's compare value register, if it has 0xffff then it is just counting overflows. For PPM out, lib's logic never allows value > 60000 in compare register.

mjs513
10-25-2019, 01:40 PM
I started to take a look at the library. Not going to be as easy to integrate as the FreqCount lib was. Why - everything is so integrated to the FTM timers that I would be having ifdefs all over the place. But that's just an initial reaction :)

As for which pin is Rx and which is Tx, don't think that will be a problem. In the lib there are 2 classes, one for input and one for output. In each class you have to specify which pin is used for capture and which is used for compare.

So this is going to be project - unless I just create a pulseposition_t4 lib and just use the same function calls - would be cleaner.

mjs513
10-26-2019, 05:14 PM
@manitou and others

SOS :)

Started working on incorporating your POC into a pulse position lib for the T4 with the ultimate goal of then incorporating it back into a master branch but running into an issue with using "attachInterruptVector" from within a class. And this pretty much will show my ignorance with using interrupts like this :( --- but I am learning.

Since I like doing things in steps I started with the PulsePositionOutputClass. In part in have in the begin:

attachInterruptVector(IRQ_QTIMER1, isrTimer1);
TMR1_CSCTRL0 &= ~(TMR_CSCTRL_TCF1); // clear
TMR1_CSCTRL0 |= TMR_CSCTRL_TCF1EN; // enable interrupt
NVIC_SET_PRIORITY(IRQ_QTIMER1, 32);
NVIC_ENABLE_IRQ(IRQ_QTIMER1);

On initial testing you will get an error that you can declare "isrTimer1" as a non-static class member. Ok so did a little searching and came across this which didn't work either:

https://stackoverflow.com/questions/41443720/how-to-create-an-isr-in-an-arduino-class

I figured I would have to eventually address the issue of multiple instances of the isr but this was just an initial test, and would have to do what @Paul did in the current pulse position library. Then I decided to follow the link on his trick:

// some explanation regarding this C to C++ trickery can be found here:
// http://forum.pjrc.com/threads/25278-Low-Power-with-Event-based-software-architecture-brainstorm?p=43496&viewfull=1#post43496

But I guess the real question I have is if I am not attaching an interrupt using attachInterruptVector how does the timer know to use the interrupt function as in the case of current lib and then port that over to the T4 Quad timer use case.

Right now this is the only thing that is holding me up.

EDIT: just did a kludge and set the isr up like was done in intervaltimer.cpp and it seemed to work. But still have to do more on this one. Just using pin 10:

278 : 600.08 1500.05 759.28 1500.05 1500.05 1234.61
279 : 600.08 1500.05 759.28 1500.05 1500.05 1234.61
280 : 600.08 1500.05 759.28 1500.05 1500.05 1234.61
281 : 600.08 1500.05 759.28 1500.05 1500.05 1234.61
282 : 600.08 1500.05 759.28 1500.05 1500.05 1234.61
283 : 600.08 1500.05 759.28 1500.05 1500.05 1234.61 so far so good more to follow.

defragster
10-26-2019, 06:34 PM
I started to take a look at the library. Not going to be as easy to integrate as the FreqCount lib was. Why - everything is so integrated to the FTM timers that I would be having ifdefs all over the place. But that's just an initial reaction :)

As for which pin is Rx and which is Tx, don't think that will be a problem. In the lib there are 2 classes, one for input and one for output. In each class you have to specify which pin is used for capture and which is used for compare.

So this is going to be project - unless I just create a pulseposition_t4 lib and just use the same function calls - would be cleaner.

When I cruised the FreqMeasure code it had simple looking top class - that has #ifdef Spaghetti underlying it. Here is a glance toward the ARM half ...


void FreqMeasureClass::begin(void)
uint8_t FreqMeasureClass::available(void)
uint32_t FreqMeasureClass::read(void)


#if defined(__AVR__)
// ...
#elif defined(__arm__) && defined(TEENSYDUINO)
void FTM_ISR_NAME (void)

It uses a generic name for _ISR that maps out, and the various Teensy Specific setup, read and the _isr was all blanketed in #ifdefs so it fell out clean on the top - but a bit of a cat herding underneath.


...\hardware\teensy\avr\libraries\FreqMeasure\util \FreqMeasureCapture.h


#if defined(CAPTURE_USE_FTM1_CH0)
#define FTM_SC_VALUE (FTM_SC_TOIE | FTM_SC_CLKS(1) | FTM_SC_PS(0))
#define FTM_ISR_NAME ftm1_isr
// …

#elif defined(CAPTURE_USE_FTM1_CH1)
#define FTM_SC_VALUE (FTM_SC_TOIE | FTM_SC_CLKS(1) | FTM_SC_PS(0))
#define FTM_ISR_NAME ftm1_isr
// …

#elif defined(CAPTURE_USE_FTM2_CH0)
#define FTM_SC_VALUE (FTM_SC_TOIE | FTM_SC_CLKS(1) | FTM_SC_PS(0))
#define FTM_ISR_NAME ftm2_isr
// …

#elif defined(CAPTURE_USE_FTM2_CH1)
#define FTM_SC_VALUE (FTM_SC_TOIE | FTM_SC_CLKS(1) | FTM_SC_PS(0))
#define FTM_ISR_NAME ftm2_isr
// …

#elif defined(CAPTURE_USE_FLEXPWM4_CH0A)
#define FTM_ISR_NAME flexpwm_4_0_isr
void flexpwm_4_0_isr(void);
// …

mjs513
10-27-2019, 12:09 AM
@defragster - @manitou

Ok spent most of the day playing with the output portion to make it work on all channels and all timers. Also made it generic enough so if we get more timer pins can be easily added. Right now I have it working on pins 10,11,12,13,14,15,18 and 19. Got something wrong with using pins and 6and 9 but will eventually figure that one out. Here is what I have so far in terms of a library:
18020

I have this sketch on one T4:

#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX)
#include <PulsePosition_t4.h>

PulsePositionOutput myOut;

void setup()
{
Serial.begin(115200);
delay(4000);
myOut.begin(9);

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);
}

void loop() {

} and @manitou's pulseinput example sketch :) Ok enough for now.

defragster
10-27-2019, 12:22 AM
Nice work @mjs513 - re: pjrc.com/teensy/td_libs_PulsePosition.html (https://www.pjrc.com/teensy/td_libs_PulsePosition.html)

How are you seeing it work?

mjs513
10-27-2019, 02:20 AM
Nice work @mjs513 - re: pjrc.com/teensy/td_libs_PulsePosition.html (https://www.pjrc.com/teensy/td_libs_PulsePosition.html)

How are you seeing it work?

Still a bunch to do - right now just playing. Only tested output so far with the 6 channel example - but so far its working as it should. Will still have to incorporate the framepin for using the shift register but trying to get the timer calls down to one set up based on pin. Still too early in testing.

mjs513
10-27-2019, 02:54 AM
@defragster

Am I reading it right that I can only transmit on 1 Tx at a time? So I can't really do:

myout.write(11, 1400.01);
myout1.write(6, 600.00); Don't think the code supports it?

defragster
10-27-2019, 03:50 AM
@defragster

Am I reading it right that I can only transmit on 1 Tx at a time? So I can't really do:

myout.write(11, 1400.01);
myout1.write(6, 600.00); Don't think the code supports it?

Not sure where you are reading:: "Teensy 3.1 supports up to 8 simulaneous PPM streams with up to 16 signals per stream. " and "Teensy-LC supports up to 6 simulaneous PPM streams with up to 16 signals per stream. "

manitou
10-27-2019, 09:57 AM
@defragster - @manitou

Got something wrong with using pins and 6and 9 but will eventually figure that one out.

OK, confirmed with scope your zip file works on pin 12 and does NOT work on pin 6.
i modified another quadtimer test sketch i had to use pin 6, i got PWM working on pin 6 using QT4_1 -- so hardware works.
quick visual inspection of zip files didn't reveal anything broken about pin 6 and 9 ... yet

manitou
10-27-2019, 10:13 AM
this fixes pin 6 and 9, change <= to == :) so it reads

} else if(txPin == 14 || txPin == 15 || txPin == 18 || txPin == 19) {

mjs513
10-27-2019, 11:01 AM
this fixes pin 6 and 9, change <= to == :) so it reads

} else if(txPin == 14 || txPin == 15 || txPin == 18 || txPin == 19) {

@manitou - thanks for the sanity check. I caught that last night before I crashed for the night. Started work on it again this morning but running into a problem with getting more than 1 pin sending data but I think I know whats causing that - have to figure out Paul's trickery with the ISRs so that the pulse buffers aren't conflicting. Can fix it but then would be limiting it to 4 transmit and 4 receive.

EDIT: ok think I figured it out enough to try and implement it. Had to read on the FTM timers though. FTM0 is one timer module with 8 channels as opposed to what we are dealing with - 4 timers with 4 channels max so just a bit more complicated - so we are going to have to deal with 4 ISRs - ok. Not sure I will get it implemented today - will be tied up with family most of the day.

KurtE
10-27-2019, 01:56 PM
@mjs513, @defragster, @manitou - Sorry I am late to the game ;)

Not sure if makes sense for another person to jump in as I already probably have enough diversions :D
Will be interested when we get to PulsePosition Input as I will be at some point wanting to adapt a robot to using a RC setup, and I have one that outputs a single PPM output...

One of the issues with multiple writes, I think is that all of them are being driven by by one or more global variables, where instead maybe the need to be instance variables? and/or per channel variables?

Example:

static void isrTimer1()
{
IMXRT_TMR1.CH[timer_channel].CSCTRL &= ~(TMR_CSCTRL_TCF1); // clear compare interrupt
ticks++;

if (state == 0) {
// pin was just set high, schedule it to go low

I marked a couple that I think may have issue with multiple things active, there may be others, or they may be fine?

But I am guessing, that the ISRS need to maybe do something like either look at some Timer status register to see which timer(s) are triggered (which I did not see) or look through the channel registers (SCTRL?), see which ones are triggered, and compare it to which ones you have active objects on, and maybe figure out which object this corresponds to, and then maybe call off to a member ISR method, which does the work and have all of the state information , like lists of pulses... as member variables? But again I am just guessing as I have not done much at all with the timer code.

mjs513
10-27-2019, 02:03 PM
@mjs513, @defragster, @manitou - Sorry I am late to the game ;)

Not sure if makes sense for another person to jump in as I already probably have enough diversions :D
Will be interested when we get to PulsePosition Input as I will be at some point wanting to adapt a robot to using a RC setup, and I have one that outputs a single PPM output...

One of the issues with multiple writes, I think is that all of them are being driven by by one or more global variables, where instead maybe the need to be instance variables? and/or per channel variables?

Example:

static void isrTimer1()
{
IMXRT_TMR1.CH[timer_channel].CSCTRL &= ~(TMR_CSCTRL_TCF1); // clear compare interrupt
ticks++;

if (state == 0) {
// pin was just set high, schedule it to go low

I marked a couple that I think may have issue with multiple things active, there may be others, or they may be fine?

But I am guessing, that the ISRS need to maybe do something like either look at some Timer status register to see which timer(s) are triggered (which I did not see) or look through the channel registers (SCTRL?), see which ones are triggered, and compare it to which ones you have active objects on, and maybe figure out which object this corresponds to, and then maybe call off to a member ISR method, which does the work and have all of the state information , like lists of pulses... as member variables? But again I am just guessing as I have not done much at all with the timer code.

Morning @KurtE :)

Your guess is exactly right about the ISRs. The current implementation was just so I could get something working that I could play with the setup structure that I wanted to use. In the process of converting the whole thing to what Paul used and explained in: https://forum.pjrc.com/threads/25278-Low-Power-with-Event-based-software-architecture-brainstorm?p=43496&viewfull=1#post43496. Think the register you have to check is the CSCTRL register for each timer and channel.

Glad you decided to play along - you know me - I can do but it usually takes me a lot longer to understand whats going on and to get it right.

EDIT: just a status. Used this for the Timer base addresses:

IMXRT_TMR_t* TMR[] = {&IMXRT_TMR4,&IMXRT_TMR4,&IMXRT_TMR1,&IMXRT_TMR1,&IMXRT_TMR1,&IMXRT_TMR2, &IMXRT_TMR3,&IMXRT_TMR3,&IMXRT_TMR3,&IMXRT_TMR3}; and made the changes in the lib and it worked. All keyed off of idx_channel. Let me know if you want me to post the latest and greatest that I have when you want to start playing :)

KurtE
10-27-2019, 02:32 PM
@mjs513 - You do great stuff! Sometimes at least for myself it has a great benefit to be able to bounce ideas and like off of others as it helps figures things out quicker...

My guess is to start off with, you could probably have your init code fill in: PulsePositionOutput * PulsePositionOutput::list[10];
With a pointer to this for the channel that you are setting up.

You could then simply do something in each of your ISRs, like:

static void isrTimer1()
{
if ((IMXRT_TMR1.CH[0].CSCTRL & TMR_CSCTRL_TCF1)) && PulsePositionOutput::list[2]) {
PulsePositionOutput::list[2]->isr();
IMXRT_TMR1.CH[0].CSCTRL &= ~(TMR_CSCTRL_TCF1);
}
if ((IMXRT_TMR1.CH[1].CSCTRL & TMR_CSCTRL_TCF1)) && PulsePositionOutput::list[4]) {
PulsePositionOutput::list[4]->isr();
IMXRT_TMR1.CH[1].CSCTRL &= ~(TMR_CSCTRL_TCF1);
}
if ((IMXRT_TMR1.CH[2].CSCTRL & TMR_CSCTRL_TCF1)) && PulsePositionOutput::list[3]) {
PulsePositionOutput::list[3]->isr();
IMXRT_TMR1.CH[2].CSCTRL &= ~(TMR_CSCTRL_TCF1);
}
asm volatile ("dsb"); // wait for clear memory barrier
}

Could be more table driven but might work...

mjs513
10-27-2019, 02:36 PM
@mjs513 - You do great stuff! Sometimes at least for myself it has a great benefit to be able to bounce ideas and like off of others as it helps figures things out quicker...

My guess is to start off with, you could probably have your init code fill in: PulsePositionOutput * PulsePositionOutput::list[10];
With a pointer to this for the channel that you are setting up.

You could then simply do something in each of your ISRs, like:

static void isrTimer1()
{
if ((IMXRT_TMR1.CH[0].CSCTRL & TMR_CSCTRL_TCF1)) && PulsePositionOutput::list[2]) {
PulsePositionOutput::list[2]->isr();
IMXRT_TMR1.CH[0].CSCTRL &= ~(TMR_CSCTRL_TCF1);
}
if ((IMXRT_TMR1.CH[1].CSCTRL & TMR_CSCTRL_TCF1)) && PulsePositionOutput::list[4]) {
PulsePositionOutput::list[4]->isr();
IMXRT_TMR1.CH[1].CSCTRL &= ~(TMR_CSCTRL_TCF1);
}
if ((IMXRT_TMR1.CH[2].CSCTRL & TMR_CSCTRL_TCF1)) && PulsePositionOutput::list[3]) {
PulsePositionOutput::list[3]->isr();
IMXRT_TMR1.CH[2].CSCTRL &= ~(TMR_CSCTRL_TCF1);
}
asm volatile ("dsb"); // wait for clear memory barrier
}

Could be more table driven but might work...

Thanks. Cool - will give it a try. Learned a long time ago that you learn a lot more by trying things to see if they work or not.

KurtE
10-27-2019, 02:41 PM
Thanks. Cool - will give it a try. Learned a long time ago that you learn a lot more by trying things to see if they work or not.

FYI - I am not sure if it will help or not, but another sort of example of array of this pointers and ISRs and using 'this' is in our st7735_t3 code, with the setup to do DMA operations, as we have an array of this pointers associated one per each SPI buss.

mjs513
10-27-2019, 02:45 PM
FYI - I am not sure if it will help or not, but another sort of example of array of this pointers and ISRs and using 'this' is in our st7735_t3 code, with the setup to do DMA operations, as we have an array of this pointers associated one per each SPI buss.

Will take a look - don't believe in reinventing the wheel - maybe just rotating them :)

Here is what I have in case you want to play, still have a lot to do on it - but once ISRs is fixed then we are off to the races and the Input section will go easier:

KurtE
10-27-2019, 05:04 PM
Hi @mjs513 still a WIP but what do you think of these types of changes, using hardware structure... I have not tried running it yet.... Game starting ;)18025

I tried to get everything in begin to work with new table of hardware structure...

FYI your arrays I believe are off, i.e. I don't think pin 16 belongs in the first list, as it has 1 more item then your other lists.

My structure/array is sort of setup to replace all of them... But again I have not completed, was interested in your first read to see what you think

mjs513
10-27-2019, 05:13 PM
Hi @mjs513 still a WIP but what do you think of these types of changes, using hardware structure... I have not tried running it yet.... Game starting ;)18025

I tried to get everything in begin to work with new table of hardware structure...

FYI your arrays I believe are off, i.e. I don't think pin 16 belongs in the first list, as it has 1 more item then your other lists.

My structure/array is sort of setup to replace all of them... But again I have not completed, was interested in your first read to see what you think

Just sat down when I got your message but beside home distractions my little one doesn't want to leave me alone today :). So will be off in a few.

Took a quick look and it looks great. That's exactly what I was shooting for eventually. Will have to give it a try later, but it should work.

BTW. You are correct pin 16 shouldn't have been in the list. I used your pin spreadsheet to get the quad timer pins so the only allowable pins are: 6,9,10,11,12,13,14,15,18,and 19 for now :)

Thanks Kurt - really appreciate the effort.

manitou
10-27-2019, 05:30 PM
Hi @mjs513 still a WIP but what do you think of these types of changes, using hardware structure... I have not tried running it yet.... Game starting ;)18025


Re: PulsePosition.h

Unless you changed additional logic, based on Paul's PulsePosition.h, you need +1 in your pulse vector dimensions

uint32_t pulse_width[PULSEPOSITION_MAXCHANNELS+1];
uint32_t pulse_buffer[PULSEPOSITION_MAXCHANNELS+1];
element [0] contains long trailing space duration.

mjs513
10-27-2019, 07:16 PM
@KurtE

Just gave it a try for some reason not working. I did check to see if the appropriate ISR was firing and it was but not showing on the Scope ? Have to go but will be back.

KurtE
10-27-2019, 07:21 PM
@mjs513 - I am still doing some hacking now...

Was hacking up ISRs...

And also I have not actually tried running it yet...

KurtE
10-27-2019, 08:25 PM
Hi again:

Sorry was detained... Here is an update to the code.

I have not tried it yet:18026

I hacked up the ISRs to maybe... That is as part of the begin, I did save away the this pointer and then did some quick and dirty, test to see if we have an object and I think that ISR has triggered, then call the member ISR. Made a copy of one of the other ISRs where I hopefully tried to remap the hardware stuff to the hardware table.

Assuming that any of this works, then probably I am guessing next step is to move most of the other global data into the instance variables. Things like state, the pulse widths...

And then update the write method to go to those settings...

EDIT: I have tried running this, and like you I am not seeing anything on pin 9...
I did bracket the ISRs with a digital writes, like:

void PulsePositionOutput::isrTimer4()
{
digitalWriteFast(2, HIGH);
if (list[0] && (IMXRT_TMR4.CH[1].CSCTRL & TMR_CSCTRL_TCF1)) {IMXRT_TMR4.CH[1].CSCTRL &= ~(TMR_CSCTRL_TCF1); list[0]->isr();}
if (list[1] && (IMXRT_TMR4.CH[2].CSCTRL & TMR_CSCTRL_TCF1)) {IMXRT_TMR4.CH[2].CSCTRL &= ~(TMR_CSCTRL_TCF1); list[1]->isr();}
asm volatile ("dsb"); // wait for clear memory barrier
digitalWriteFast(2, LOW);
}

And I am getting ISRs. Not sure if correct ones yet, but...
So now wondering when/where does the IO pin get configured to be driven by the timer...

Investigating

KurtE
10-27-2019, 08:49 PM
@mjs513 - I think that part is fixed. I #if 1/#else too much of the old code away and did not configure pin...

Now showing some output...

So I think I will celebrate and go hook up wood chipper to small tractor

mjs513
10-27-2019, 10:34 PM
@KurtE

Yep you got it fixed! In the config as posted in post #54 I tested each QT pin and it worked, i.e., got the expected output as seen on the other T4.

I also did a bunch of clean up to the code (got rid of all the old stuff as well as moving the all the globals back into the .h file). It still works on all pins. I also tested outputting to three channels from with the sketch and SUCCESS! Here is the test sketch:

#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX)
#include <PulsePosition_t4.h>

PulsePositionOutput myOut;
PulsePositionOutput myOut1;
PulsePositionOutput myOut2;

void setup()
{
Serial.begin(115200);
delay(2000);
myOut.begin(12);
myOut1.begin(13);
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);
myOut2.write(1, 634.56);

}

void loop() {

} Here is the updated lib for output only. Now back to other things going on.

BTW. Forgot to say - really like what you did with the changes - good learning exercise for me.

mjs513
10-28-2019, 12:15 AM
@KurtE,

Ok - I got an initial pass at incorporating PulsePositionInput class into the lib. Did a quick test but have something is off. It is receiving data on the pin but the values are wrong - have some debugging to do - pretty sure my ISRs wrong for the this setup - have some debugging to do unless you beat me too it. This is the sketch I am using to test input:

#include <PulsePosition_t4.h>

// Simple loopback test: create 1 output to transmit
// test pulses, and 1 input to receive the pulses
PulsePositionInput myIn;

void setup() {
myIn.begin(11);

}

int count=0;

void loop() {
int i, num;

// 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();
}
}

latest and greatest attached. Like I said its just a quick and dirty incorporation of the pulse input class functions. Now for some sleep.

KurtE
10-28-2019, 01:38 AM
@mjs513 - I don't think I have time tonight to do much here... Other distractions.

One thing I was thinking about was the interaction between the PulsePositionInput and PulsePositionOutput.

Imagine if your test case was to have a test sketch with maybe Pin 10 as an output and pin 11 as an input and you wanted to test by connecting a wire between the two pins.

Problem is, that is they both would want the same Interrupt vector and different code.

What I was thinking of trying was to create a base clase like: PulsePositionBase.

Maybe something like:

class PulsePositionBase
{

public:

protected:
static PulsePositionBase *list[10];
typedef struct {
uint8_t pin;
uint8_t channel;
volatile IMXRT_TMR_t* tmr;
volatile uint32_t *clock_gate_register;
uint32_t clock_gate_mask;
IRQ_NUMBER_t interrupt;
void (*isr)();

} TMR_Hardware_t;
static const TMR_Hardware_t hardware[];

// member variables...
virtual void isr();
// static class functions

static void isrTimer1();
static void isrTimer2();
static void isrTimer3();
static void isrTimer4();
};

Then base both the other classes on this. They would share the same hardware list, and the list of objects would be shared, and the ISR would be virtual so both could implement... So far it looks like your testing to know which if an ISR happened on each channel is the same for Input and Output, so should just work. If it turns out that they may have different flags we could change test/clear in the ISRs...

Hope that makes sense?

manitou
10-28-2019, 09:44 AM
@KurtE,

Ok - I got an initial pass at incorporating PulsePositionInput class into the lib. Did a quick test but have something is off. It is receiving data on the pin but the values are wrong - have some debugging to do - pretty sure my ISRs wrong for the this setup - have some debugging to do unless you beat me too it.
Just a visual inspection, in Input begin() you need

write_index = 255;
available_flag = false;
In my hack, i had those in setup() .... ugly
but you might also compare your code to Paul's PulsePosition code.

I just noticed in Paul's PulsePostion code, he has Input pulse buffers sized at PULSEPOSITION_MAXCHANNELS and Output pulse buffers sized at PULSEPOSITION_MAXCHANNELS+1. I know the Output buffers needs to be +1, and I'm thinking the Input buffers may need to be +1 ... bug? further study required.

EDIT: i think Input pulse buffers should be sized PULSEPOSITION_MAXCHANNELS+1 and in the Input isr

if (write_index < PULSEPOSITION_MAXCHANNELS) {
should be
if (write_index <= PULSEPOSITION_MAXCHANNELS) {

EDIT 2: upon further review, i think the Input pulse buffer logic is OK

mjs513
10-28-2019, 11:34 AM
@KurtE - Makes absolute sense in what you propose. Notice we were duplicating that between Input and output.

@manitou - made the changes in your post.

Ok. Made one change to the ISR flags that did improve the issue that I originally saw. Went from:

if (list[5] && (IMXRT_TMR2.CH[0].CSCTRL & TMR_CSCTRL_TCF1)) {IMXRT_TMR2.CH[0].CSCTRL &= ~(TMR_CSCTRL_TCF1); list[5]->isr();} to
if (list[2] && (IMXRT_TMR1.CH[0].CSCTRL & TMR_CSCTRL_TCF1)) { list[2]->isr();} Notice we were clearing the flag too early. In the ISR there was a test using the flag to determine when the overflow occurred. Making that change and using only a single frequency of 600.03 on pin 13 I am now seeing:


3284 : 2347.71
3285 : 600.08
3286 : 600.08
3287 : 2347.71
3288 : 600.08
3289 : 600.08
3290 : 2347.71
3291 : 600.08
3292 : 600.08 Which is partially correct but something seems not be clearing since I am getting that 2347.71 instead of the 600.0x. Still looking.

manitou
10-28-2019, 12:21 PM
I don't think it will affect what you are seeing, but upon further review, i think the Input pulse buffer logic and buffer sizes are OK

mjs513
10-28-2019, 12:45 PM
I don't think it will affect what you are seeing, but upon further review, i think the Input pulse buffer logic and buffer sizes are OK

Not a problem - tried it both ways and no change in what I am seeing.

KurtE
10-28-2019, 01:06 PM
@mjs513 @manitou - I could be completely barking up the wrong tree (been known to happen), especially in systems like the timers that I have not done much with (except use)

But I am wondering about on Input capture, setup and flag testing of the registers (SCTRL and CSTRL) ... Sorry in advance for rambling

In particular for Output I see we set:

//TMR1_SCTRL0 = TMR_SCTRL_OEN | TMR_SCTRL_OPS to make falling
if(outPolarity == 0){
tmr_ch->SCTRL = TMR_SCTRL_OEN | TMR_SCTRL_OPS;
} else {
tmr_ch->SCTRL = TMR_SCTRL_OEN ;
}

tmr_ch->CSCTRL = TMR_CSCTRL_CL1(1);
attachInterruptVector(hardware[idx_channel].interrupt, hardware[idx_channel].isr);
tmr_ch->CSCTRL &= ~(TMR_CSCTRL_TCF1); // clear
tmr_ch->CSCTRL |= TMR_CSCTRL_TCF1EN; // enable interrupt


On Input we see:


tmr_ch->SCTRL |= TMR_SCTRL_IEFIE; // enable compare interrupt
tmr_ch->CSCTRL = TMR_CSCTRL_TCF1EN; // enable capture interrupt


Now in ISRs:

Output:


if (list[2] && (IMXRT_TMR1.CH[0].CSCTRL & TMR_CSCTRL_TCF1)) {IMXRT_TMR1.CH[0].CSCTRL &= ~(TMR_CSCTRL_TCF1); list[2]->isr();}


Input:


if (list[2] && (IMXRT_TMR1.CH[0].CSCTRL & TMR_CSCTRL_TCF1)) {IMXRT_TMR1.CH[0].CSCTRL &= ~(TMR_CSCTRL_TCF1); list[2]->isr();}

I get sort of confused in these cases the relationship here between CSCTRL and SCTRL:
That is setting the TMR_SCTRL_IEFIE, looks like it would be doing the interrupt and setting the IEF flag in SCTRL regegister... Not sure what the TMR_CSCTRL_TCF1EN register/bit is doing?

Again probably wrong tree!

mjs513
10-28-2019, 01:34 PM
@KurtE

You and me both :). Keep going through the manual and trying things as I am reading but still confused.

In one of the earlier messages @manitou wrote:

Excellent. There are 10 quadtimer pins on T4. One problem requiring additional logic with both quadtimer PPM out and in in the same lib is that I never could get quadtimer Overflow interrupt to work (??). Counter in overflow interrupt is used to generate 32-bit counter for capture values. I had to use compare-value interrupt (0xffff) to count overflows, BUT compare-value interrupt is used in PPM out. So you'd need to know which pin is in capture mode and which pin is in compare mode to follow the proper path in the ISR -- maybe just look at timer's compare value register, if it has 0xffff then it is just counting overflows. For PPM out, lib's logic never allows value > 60000 in compare register. Have to digest this one.

EDIT: just noticed something else that I have to look at. If I change input pin to 12 I get nothing so only 11 is working with the code as it stands. Ok - need more coffee

KurtE
10-28-2019, 02:10 PM
@mjs513 and ...

I do think the input ISR settings/handling is screwed up... Will play some more.

I hacked up last nights version to interrupt on input ISR on pin 3 instead of 2, and then did a quick and dirty version of pin 9, to 11 so two different timers involved:

#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX)
#include <PulsePosition_t4.h>

PulsePositionOutput myOut;
PulsePositionInput myIn;
uint32_t count = 0;
void setup()
{
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
Serial.begin(115200);
delay(2000);
// Make sure on different timers...
myOut.begin(9);
myIn.begin(11);
myOut.write(1, 750);
}
uint32_t last_in_avail_time = 0;
void loop() {
int i, num;

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

796(0): 926.72
797(0): 1026.75
798(0): 1026.75
799(0): 1026.75
800(0): 926.72
801(0): 1026.75
802(0): 1026.75
803(0): 926.72
804(0): 1026.75
805(0): 1026.75
806(0): 926.72
807(0): 1026.75
808(0): 1026.75


Then hooked up LA to pins 9 (and 11 as they are jumpered to each other and 2 and 3...

If you then look at LA output:
You will see there is just one interrupt on the output and a ton of them on input...
18036

Note: I am getting ton of outputs... With time between 0 micros...

mjs513
10-28-2019, 02:23 PM
@KurtE

It seems to be better when using T4 - T4. Just tried loopback as well on 1 T4 with the version I have from this morning with just 1 output frequency and its seems to be always in the 2XXX ranges for a sketch freq of 600.08.

Think this may be going to back to what I quoted @manitou said in https://forum.pjrc.com/threads/57894-Teensyduino-1-48-Beta-3?p=220036&viewfull=1#post220036.

Also if you change from pin 11 to pin 12 its not doing the capturing. Was trying to debug it - ISRs are firing correctly but for other that pin 11 the second IF criterion is never satisfied.

EDIT: I am tx on pin 13 and rx on pin 11.

EDIT2: I just put a scope on pin 13 while running the sketch and the signal is affected by the input config/ISR
18037

Without attaching pin 11 (rxpin) the signal looks like the 2 narrow pulses in the middle of the image

mjs513
10-28-2019, 02:57 PM
@KurtE and others...
I just used the lib to setup output on pin 9 in @manitou's original pulsepositioninput sketch. Pin 9 is outputting 600.03 and the sketch is reading 600.08. Heres the sketch for your reference:


// 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 (TMR1_CSCTRL2 & TMR_CSCTRL_TCF1) { // compare rollover
TMR1_CSCTRL2 &= ~(TMR_CSCTRL_TCF1); // clear
overflow_count++;
overflow_inc = true;
}
if (TMR1_SCTRL2 & TMR_SCTRL_IEF) { // capture
uint32_t val, count;
TMR1_SCTRL2 &= ~(TMR_SCTRL_IEF); // clear
val = TMR1_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_QTIMER1(CCM_CCGR_ON);

TMR1_CTRL2 = 0; // stop
TMR1_LOAD2 = 0;
TMR1_CSCTRL2 = 0;
TMR1_LOAD2 = 0; // start val after compare
TMR1_COMP12 = 0xffff; // count up to this val, interrupt, and start again
TMR1_CMPLD12 = 0xffff;

TMR1_SCTRL2 = TMR_SCTRL_CAPTURE_MODE(1); //rising
attachInterruptVector(IRQ_QTIMER1, my_isr);
TMR1_SCTRL2 |= TMR_SCTRL_IEFIE; // enable compare interrupt
TMR1_CSCTRL2 = TMR_CSCTRL_TCF1EN; // enable capture interrupt
NVIC_SET_PRIORITY(IRQ_QTIMER1, 32);
NVIC_ENABLE_IRQ(IRQ_QTIMER1);
TMR1_CTRL2 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | TMR_CTRL_SCS(2) | TMR_CTRL_LENGTH ; // prescale
*(portConfigRegister(11)) = 1; // ALT 1
}

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(TMR1_SCTRL2);
PRREG(TMR1_CSCTRL2);
PRREG(TMR1_CTRL2);
PRREG(TMR1_LOAD2);
PRREG(TMR1_COMP12);
PRREG(TMR1_CMPLD12);
PRREG(TMR1_COMP22);
PRREG(TMR1_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();
}
}

manitou
10-28-2019, 02:58 PM
I get sort of confused in these cases the relationship here between CSCTRL and SCTRL:
That is setting the TMR_SCTRL_IEFIE, looks like it would be doing the interrupt and setting the IEF flag in SCTRL regegister... Not sure what the TMR_CSCTRL_TCF1EN register/bit is doing?


SCTRL is the capture interrupt, only used by PPM in

CSCTRL is the compare interrupt used by PPM out AND used by PPM In to count rollovers of timer for 32-bit count. That was my concern in post #30 (https://forum.pjrc.com/threads/57894-Teensyduino-1-48-Beta-3?p=219808&viewfull=1#post219808) where if you have a sketch doing both PPM in and PPM out on the same TMRx, then the ISR logic has to differentiate the compare interrupt based on ??, one case bump the overflow count or the other case fall into the "state" management logic ....

in Paul's PulsePosition, a timer overflow interrupt is used to bump the overflow count, but I never could get timer overflow to fire with quadtimers???, so i reverted to using a compare interrupt (compare value 0xffff)

manitou
10-28-2019, 04:03 PM
FWIW, i added framePin support to my hack ppmoutq.ino. updated github.
https://github.com/manitou48/teensy4/blob/master/ppmoutq.ino
tested on scope with pin 2 as framePin. scope output looks the same as T3.2 PulsePosition using framePin

KurtE
10-28-2019, 04:31 PM
Yep - sort of confusing...

@mjs513 and @manitou -
Wondering about this line:

tmr_ch->CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | TMR_CTRL_SCS(2) | TMR_CTRL_LENGTH ; // prescale
Which goes back to sample line:

TMR1_CTRL2 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | TMR_CTRL_SCS(2) | TMR_CTRL_LENGTH ; // prescale

Where maybe the (2) implies that this is for logical input pin 2? If so this would need to change to be the logical channel on the timer?

Or put another way with our table extract


{11,2, &IMXRT_TMR1, &CCM_CCGR6, CCM_CCGR6_QTIMER1(CCM_CCGR_ON), IRQ_QTIMER1, &PulsePositionInput::isrTimer1 },
{12,1, &IMXRT_TMR1, &CCM_CCGR6, CCM_CCGR6_QTIMER1(CCM_CCGR_ON), IRQ_QTIMER1, &PulsePositionInput::isrTimer1 },
:
Might work for pin 11, but for pin 12, You would need TMR_CTRL_SCS(1) ?

Still looking, may for fun see if Overflow works...
On ISR, I can see having it do something like:

if (list[3] && (IMXRT_TMR1.CH[2].CSCTRL & TMR_CSCTRL_TCF1)
|| (IMXRT_TMR1.CH[2].SCTRL & (TMR_SCTRL_IEF | TMR_SCTRL_IEFIE) == (TMR_SCTRL_IEF | TMR_SCTRL_IEFIE))) {
list[3]->isr();
}

Still playing, but may be off doing some other stuff soon

manitou
10-28-2019, 05:00 PM
Re: TMR_CTRL_SCS(2)

I looked at TMR_CTRL_SCS(2) last night and decided it was harmless, but I just removed it, and input doesn't work. So that value needs to match the channel of the timer for the T4 pin you've selected. in my hacked sketch, i was using T4 pin 11 which is qtmr 1 ch 2, hence the "2"

my first test sketch qtmr_capture.ino was based on SDK example, so that's where i got most of required register settings.

KurtE
10-28-2019, 05:16 PM
@mjs513 @manitou and others

I think I have had some success now:

This sketch is showing some reasonable outputs:


#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX)
#include <PulsePosition_t4.h>

PulsePositionOutput myOut;
PulsePositionInput myIn;
uint32_t count = 0;
void setup()
{
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
Serial.begin(115200);
delay(2000);
// Make sure on different timers...
myOut.begin(9);
myIn.begin(11);
myOut.write(1, 750);
}
uint32_t last_in_avail_time = 0;
void loop() {
int i, num;

// Every time new data arrives, simply print it
// to the Arduino Serial Monitor.
num = myIn.available();
if (num > 0) {
uint32_t cur_time = micros();
count = count + 1;
Serial.print(count);
Serial.print("(");
Serial.print(cur_time-last_in_avail_time, DEC);
last_in_avail_time = cur_time;
Serial.print("): ");
for (i=1; i <= num; i++) {
float val = myIn.read(i);
Serial.print(val);
Serial.print(" ");
}
Serial.println();
}
}
Where I have pin 9 connected to pin 11...

Still have separete classes with their own ISRs so can't have them both active. Although I think I setup the input ISR to hooks setup that should be able to use for both...

KurtE
10-28-2019, 07:42 PM
FYI - I create the base class and made Input and Output based off of it, and my test sketch is still working...

I am probably done for awhile... Need to go to store...

EDIT: Looks like the overflow is not happening... So capture is happening, but the value returned is missing the overlflow values so in my test case I added two more output values:
myOut.write(1, 750);
myOut.write(2, 1500);
myOut.write(3, 2250);

What I am seeing is something like:

38530(2250): 750.05
38531(18500): 1519.28
38532(19251): 502.45

mjs513
10-28-2019, 10:15 PM
@KurtE
Been playing....


FYI - I create the base class and made Input and Output based off of it, and my test sketch is still working...

I am probably done for awhile... Need to go to store...

@KurtE ….
See been busy while I was out --- really simplified the code using that base class. Have to digest it a bit more though.

Just ran a couple of quick tests with the lib in post #72:
1. pin 13 output on T4(A) to pin 11 on T4(B). (A) running single channel out of 600.03. On pin 11 of (B) I am seeing:multi-channel output when it should be only 1 channel showing:

101 : 600.08 176.37 600.08 176.37
102 : 176.37 600.08 176.37
103 : 176.37 600.08 176.37
104 : 176.37 600.08 176.37 600.08

2. pin 13 output on T4(A) to pin 11 on T4(B). (A) running mutli-channel output of 3 frequencies (600.03, 1500.00, 759.24). Catching but acting like it is 3 single frequencies:

0223 : 600.08
10224 : 1412.35
10225 : 759.28
10226 : 600.05
10227 : 759.28
10228 : 1500.05
10229 : 600.08
10230 : 759.28
10231 : 600.08
10232 : 600.08
10233 : 759.28
10234 : 600.08
10235 : 1412.35

3. Multi-pin output on (A). On (A) pin 13 sending single freq of 600.03 and pin 11 sending 634.56; (B) on pin 11 receiving since that is the only working one right now:
Output from pin 13:

24219 : 600.08 176.37 600.08 176.37
24220 : 176.40 600.08 176.37
24221 : 176.37 600.08 176.37
24222 : 176.37 600.08 176.37 600.08
24223 : 600.08 176.37 600.08 176.37
24224 : 176.37 600.08 176.37


Output from pin 11:

23379 : 634.59 141.87 634.59 141.87
23380 : 141.87 634.59 141.89
23381 : 141.87 634.59 141.87
23382 : 141.87 634.59 141.89 634.59
23383 : 634.59 141.87 634.59 141.87


Can still only get input on pin 11. No other pin works

KurtE
10-28-2019, 11:16 PM
@mjs513 - I will work on making the inputs work on different pins...

I am pretty sure I know what is going on, and what I need to do to fix...

Hint: Think of other IO pins in other subsystems that did not work...
Hint2: Look at pages like 861 (IOMUXC_QTIMER2_TIMER0_SELECT_INPUT)

mjs513
10-28-2019, 11:49 PM
@mjs513 - I will work on making the inputs work on different pins...

I am pretty sure I know what is going on, and what I need to do to fix...

Hint: Think of other IO pins in other subsystems that did not work...
Hint2: Look at pages like 861 (IOMUXC_QTIMER2_TIMER0_SELECT_INPUT) Don't need the hint - was looking for the daisy chain earlier on but when I did the search I didn't come across it - must be losing it in my old age ;)

EDIT: Not all pins are available for input using daisy chain unless I missed something, this is what I found:

IOMUXC_QTIMER2_TIMER0_SELECT_INPUT = 0x01; //pin 13
IOMUXC_QTIMER3_TIMER0_SELECT_INPUT = 0x02; //pin 19
IOMUXC_QTIMER3_TIMER1_SELECT_INPUT = 0x00; //pin 18
IOMUXC_QTIMER3_TIMER2_SELECT_INPUT = 0x01; //pin 14
IOMUXC_QTIMER3_TIMER3_SELECT_INPUT = 0x01; //pin 15

mjs513
10-29-2019, 07:17 AM
@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:

// 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();
}
}

manitou
10-29-2019, 09:59 AM
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

mjs513
10-29-2019, 10:46 AM
@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.

// 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

mjs513
10-29-2019, 12:35 PM
RE: FOUND THE HANG FOR PINS OTHER THAN 11

Hangs on this line:

//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.

manitou
10-29-2019, 12:45 PM
RE: FOUND THE HANG FOR PINS OTHER THAN 11

Hangs on this line:

//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;

KurtE
10-29-2019, 12:50 PM
Good morning...

Yep - I have seen it hang at or near there... Sometimes it goes a bit longer... before hang...

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!

KurtE
10-29-2019, 01:18 PM
FYI - I changed around my test app, to init the In before the Out and sure enough everything prints:

myIn.begin(19);
myOut.begin(9);
myOut.write(1, 750);
myOut.write(2, 1500);
myOut.write(3, 2250);



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...
18045
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

mjs513
10-29-2019, 01:42 PM
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.

KurtE
10-29-2019, 02:05 PM
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:

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...

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:

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. :o

Look at the function:

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 ((IMXRT_TMR1.CH[2].SCTRL & (TMR_SCTRL_IEF | TMR_SCTRL_IEFIE)) == (TMR_SCTRL_IEF | TMR_SCTRL_IEFIE))
return true;
return false;
}

Should be:

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;
}

mjs513
10-29-2019, 02:15 PM
@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.

KurtE
10-29-2019, 02:31 PM
@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

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...

KurtE
10-29-2019, 02:46 PM
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...

KurtE
10-29-2019, 03:24 PM
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:

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:

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:

manitou
10-29-2019, 07:12 PM
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 (https://community.nxp.com/thread/504033) confirms bug in quad timer overflow interrupt -- though it does fire if counting down. Should be documented in latest errata.

mjs513
10-29-2019, 07:14 PM
@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!

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:

#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?

mjs513
10-29-2019, 07:18 PM
Just for the record, NXP discussion (https://community.nxp.com/thread/504033) 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.

manitou
10-29-2019, 07:36 PM
So which way do we want to go now - merge this pulse position or keep a separate T4 library?

You could fix framepin support. In my test sketch, I just used digitalWrite/digitalRead to implement framepin.
https://forum.pjrc.com/threads/57894-Teensyduino-1-48-Beta-3?p=220044&viewfull=1#post220044

mjs513
10-29-2019, 07:38 PM
You could fix framepin support. In my test sketch, I just used digitalWrite/digitalRead to implement framepin.
https://forum.pjrc.com/threads/57894-Teensyduino-1-48-Beta-3?p=220044&viewfull=1#post220044

Shoot - forgot about that we everything else going on - working it now.

EDIT: Done:

18052

Still have to test but off for an errand now will do when I get back.

KurtE
10-29-2019, 07:56 PM
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:



#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:

#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...

mjs513
10-29-2019, 08:24 PM
@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.

mjs513
10-30-2019, 01:13 AM
@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
10-30-2019, 12:14 PM
UPDATE:

Incorporated the changes into the pulseposition main lib using the approach that @KurtE suggested. Gave it a quick spin and test using the loopback example with no problem. I issued a PR to @Paul:

Updated PulsePosition Lib to support T4 #7 (https://github.com/PaulStoffregen/PulsePosition/pull/7)

The local fork on GITHUB for updated lib is at: https://github.com/mjs513/PulsePosition if you all want to give it a try.

manitou
10-30-2019, 12:48 PM
@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

Change to initialize overflow interrupt instead of compare
> TMR1_SCTRL2 |= TMR_SCTRL_TOFIE; // enable oflow interrupt

change start up config to down count and no LENGTH
> TMR1_CTRL2 = TMR_CTRL_DIR | TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | TMR_CTRL_SCS(2); // prescale

In isr replace compare logic with overflow logic
> void my_isr() { // capture and underflow
> if (TMR1_SCTRL2 & TMR_SCTRL_TOF) { // underflow rollover
> TMR1_SCTRL2 &= ~(TMR_SCTRL_TOF); // clear

and in isr, flip bits when saving captured value
> val = (uint16_t)~(TMR1_CAPT2); // count up

I don't know if using the overflow interrupt rather than the compare interrupt would have simplified your ISR management.

KurtE
10-30-2019, 12:48 PM
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:

PulsePosition
=============

Multiple High-Res Input &amp; 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...)

mjs513
10-30-2019, 01:02 PM
@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.

manitou
10-30-2019, 02:58 PM
UPDATE:

Incorporated the changes into the pulseposition main lib using the approach that @KurtE suggested. Gave it a quick spin and test using the loopback example with no problem. I issued a PR to @Paul:

Updated PulsePosition Lib to support T4 #7 (https://github.com/PaulStoffregen/PulsePosition/pull/7)

The local fork on GITHUB for updated lib is at: https://github.com/mjs513/PulsePosition if you all want to give it a try.
did a quick test on your github local fork. works for me :D