Doing:

TR.P 1
DEL 6: TR.P 2

… results in about 6ms of turn on jitter for me: TR 2 is delayed by 2-8ms with respect to TR 1 when the DEL is added.

This is a variable number that changes with different metro/trigger timings.

delays and trigger pulses are handled by a single timer. separate timers could be used, but this could potentially affect the overall system performance, so it’s a tradeoff - better overall stability at the expense of delays and trigger pulses not being super accurate. this timer runs every 10ms, which is why you’re seeing jitter between 1 and 10ms.

CV updates are also handled by a timer which runs every 6ms. i’m not actually sure why in this case it can’t just update the DAC immediately, this 6ms rate is more for handling gliding. looking at the code i wonder if there is a typo here: https://github.com/monome/teletype/blob/master/module/main.c#L897

it’s the function that gets called when CV op is used. the line above sets the ADC timer to 1ms so that it triggers on the next tick. but the ADC timer handles reading the input and the knob value, not sure why it needs to be executed immediately after - i wonder if it’s supposed to be timer_manual(&cvTimer) instead?

4 Likes

Was just wondering this. Here is a build with this patched to see if that improves the chirping: teletype.hex (581.2 KB)

You will see this up to 10ms jitter on falling edges from TR.P because of the 10ms timer mentioned above, but setting the gate high for TR.P, setting TR directly, and TR.TOG are memory-mapped GPIO accesses and are very fast. If you can use an external gate source with the length you want it’s possible you may see tighter timings using $.POL 1 3 to fire on both edges and setting TR 1 STATE 1, because script triggers are driven by GPIO interrupts, STATE 1 is a GPIO read, and TR 1 x is a GPIO write.

5 Likes

great, thanks for posting a test version!

thinking more about this, having 4 dedicated timers for trigger pulses - doesn’t seem like it would affect the overall performance much. for delays this would be 32 extra timers, so a different matter. but maybe a dedicated op for one 1ms precision delay? !DEL similarly to !M op?

3 Likes

Anything that prevents short triggers from disappearing entirely would be wonderful. There is quite an audible difference between 1ms and, say, 8ms pulses when hitting a lowpass gate, so the extra precision and consistency would also be nice. But low latency leading edge signals are good enough for a lot of things, so the TR outputs are quite useful no matter what even as-is.

The CV delay is more troublesome since it falls into a very audible range and can’t be compensated for in any reasonable way.

I will try to test @csboling’s firmware version tomorrow and report back my findings. Thanks to all for their efforts, you’re the best. :slight_smile:

Real Life delayed me a little, but I can report that there is now no jitter and very little latency for CV output calls! This is a pretty big win since it means I can reliably use the onboard CV outputs for pitch. :slight_smile:

I am still seeing the effects of the 10ms loop for TR.P and DEL calls: if the metro is set to a period divisible by 10, everything looks pretty stable–any other value results in tons of jitter.

5 Likes

A little more data, this CV fix really sped stuff up:

I moved stuff to script 1 and ran the tests off an external clock so I could get a handle on total real world latency.

TR.P has maybe 40us (yes, forty microseconds) of off-to-on latency. I’d need to fire up my Rigol scope to see the jitter, it’s too small for the O’Tool+.

CV state changes have c. (edit: double the times here, I thought I was still looking at 100us/div when it was 200us/div! Max observed latency is still a very good 1ms) 200us of latency + c. 500us of jitter after this update, which is very good when we take into account the very fast & clean transitions.

@csboling @scanner_darkly @tehn … nice work, thanks so much for all you do! Teletype keeps getting better and better :slight_smile:

4 Likes

thanks for taking the measurements - it’s nice to see some concrete numbers!

2 Likes

I’ve been tracking down a new issue: Teletype is dropping events randomly. At first I thought it was my imagination, but now I can replicate it pretty easily. The scene only requires this:

TR.P 1

… and a clock fed to the corresponding script. I am giving it a 150bpm train of 1ms pulses and not always getting a pulse on TR 1, as verified by observing scope traces. It gets much worse when I interact with the grid preview mode (without grid plugged in): holding down an arrow key to move around the grid buttons causes maybe 5% of TR.P calls to fall on the floor. Dropped TO.ENV.TRIG calls are where I first noticed the issue, so it’s not limited to just the onboard TR outputs.

This is not related to the above jitter issue: I tried various values for TR.TIME in the 50-100ms range, which is well over the threshold where pulses got jittered out of existence.

Edit: running the above firmware revision and have (2) TXo and (2) TXi connected via backpack.

Is it related to the length of the incoming triggers? I have a vague recollection of another module (or several?) failing to catch short-duration triggers, and 1ms is pretty short.

1 Like

Good call, I just tried it with various input pulse lengths from 5-10ms and did not observe any dropped TR.P calls with lengths of 8ms or more. I’ll keep testing, perhaps it’s related to the 10ms cycle time?

I was using 1ms pulses to get a narrow spike on the scope for an upcoming presentation on generative sequencing techniques–this is the first time I’ve had an issue (that I noticed, anyhow) with short pulses, however.

I did a quick test and noticed dropped TR.Ps from a fast M script (M! < 20ms) when moving the cursor around the Grid pages.

I also noticed that sending a clock of certain speeds to trigger a TR.P from script 1 caused the length of Gates out of 1 to be (cyclically) variable. I wonder whether incoming triggers of certain speeds can cause dropped triggers - eg when they are spaced as a certain division/multiple of TR.TIME.

If that makes little sense, I’ll make a video later to illustrate.

1 Like

This could be a regression in 3.1.0 since the handler now checks the pin state to decide whether or not to fire the script depending on your configured $.POL. If the input is low again by the time that check happens it might not fire the script.

2 Likes

This would tally with my experience above.

Check above for a discussion of this issue. :slight_smile:

FYI, I have been working on a new scheduler core that uses custom timer adjustments with CPU cycle count feedback adjustment that does everything on a single timer. It would be millisecond accurate for all DEL, TR.P and METRO, and could guarantee execution priority and predictable timing, even with triggers (the trigger ISR flips a bit and the trigger is processed only when it wouldn’t interrupt the timing of M, DEL, etc).

CV slew update throttling is a current bugbear, insofar as producing predictable results in busy patches.

I had previously shelved the design as I read that timers were adjusted in a subsequent release and thought they might have been good enough for most applications.

If a millisecond-accurate Metro is still desirable, I could try to finish up work on it. It would have to be experimental for some time as it is a significant departure from the current scheduler.

Let me know.

7 Likes

20 characters of :heart_eyes::heart_eyes::heart_eyes::heart_eyes::heart_eyes:

Edit: I am also signing up for detailed testing with my recently upgraded Rigol scope.

1 Like

Asking here since someone here likely knows the answer:

Where in the H - E - double chopsticks is INIT_SCRIPT set!!! ??? No luck with grepping around at all …

Strangely, it is in turtle.h, accompanied by a comment on the misplacedness of this enum: https://github.com/monome/teletype/blob/38668cacaf64d696023430250339c936df6b2653/src/turtle.h#L43

1 Like

Hah, I was looking right at it but only saw the single line that grep matched–I was looking for a #define!

Adding A, B, and C scripts (and making them callable with $/SCRIPT) was pretty easy once I found that. Thanks so much!!

1 Like