Marlin on Teensy 4.0 / 4.1

Status
Not open for further replies.

TimK

Member
Hi all,

I've been running a custom version of the Marlin firmware ( https://github.com/MarlinFirmware/Marlin ) on Teensy 3.5 for a while now and it runs great.
I would like to see I could run in it on Teensy 4.0 but there's one piece I can't seem to figure out how to change for Teensy 4.0.
One thing I find particularly difficult is moving the timer code ( https://github.com/MarlinFirmware/Marlin/blob/2.0.x/Marlin/src/HAL/TEENSY35_36/timers.cpp ) from Teensy 3.5 to 4.0.

Does anyone have any idea how to get started on this or should I just read the documentation of IMXRT1062 ?

Thanks for any pointers!
 
didn't look .... but Sounds like the timers are being used low level and not through PJRC interfaces?

This github.com/luni64/TeensyTimerTool is a set of code that may show needed example or details or offer needed usage for various timers ...

The CORES for Teensy4 will have PJRC's solution for timer access as well.

Both of those might be easier to read than the manual?
 
Thank you both defragster and PhilB! Those look like very interesting things to look at!
I have no experience using hardware timers, so this is all still quite dense to go through..
Code:
TMR4_CSCTRL0 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2);
... yummy

I'm sorry if I'm asking too much, but this for example is already difficult to understand:
Code:
TMR4_COMP10 = F_BUS_MHZ * settings->steppers.pulse_delay_microseconds;
TMR4_COMP20 = F_BUS_MHZ * settings->steppers.pulse_microseconds;
TMR4_CSCTRL0 |= TMR_CSCTRL_TCF2EN;
TMR4_CTRL0 |= TMR_CTRL_OUTMODE(0b100);

What exactly do TMR4_COMP10 and TMR4_COMP20 do?

Any recommendations on how to get started with using / understanding the hardware timers?
 
First thing I would suggest, is if you have not already done so, you should download the reference manuals for the processors you are interested in. In this case T3.5 and T4.

You can get these from PJRC website: https://www.pjrc.com/teensy/datasheets.html

So in this case T4.. In this case also good place to look is in the sources: imxrt.h will give you the definitions of TMR4_... values

In this case you are talking about the Quad timers. So that is chapter 53 of the IMXRT1060RM pdf file.

TMR4_COMP10 - is the Quad Timer 4 Sub Timer 0 Compare register 1 (53.6.1) the 16 bit value:
Code:
This read/write register stores the value used for comparison with the counter value in count up mode.

Similar for TMR4_COMP20

TMR4_CSCTRL0 |= TMR_CSCTRL_TCF2EN;
Timer Compare 2 interrupt enable - generate an interrupt when TCF2 are set


TMR4_CTRL0 |= TMR_CTRL_OUTMODE(0b100);
Sets the Output mode - 100 Toggle OFLAG output using alternating compare registers

To actually understand this you probably need to read parts of that chapter in the reference manual
 
I was kind of hoping there would a more general introduction to hardware timers somewhere...
But all good, I will try going through the timer code for Teensy3.5 in Marlin (and the other code you both have suggested) and look at the manual to explain the names of the registers. Should be interesting!

A little of topic: I'm getting help from a dog and a soaring eagle, should I also change my profile pic to an animal to better fit in on this forum?
 
Not knowing - or even having looked - how the timers are used - is it possible they could be replaced with the higher level code in TeensyTimerTool or the intervalTimer where those low level details are already handled?

As for images: eagles are here - that one overhead on July 4th seemed good for here - with his feet under the translucent sunlit white tail.
 
Yes it is sort of a chicken and egg issue.

That is in your previous post you asked:
What exactly do TMR4_COMP10 and TMR4_COMP20 do?
So I pointed you to location in the manual the explains these registers. ;)

And yes I do spend a bit of time looking through these reference manuals. Especially any time I see or want to do something at the register level.

Sorry probably might answer differently if the question was, I need a timer to do X... than maybe can give a bett question.

As Defragster mentioned, it might help if we knew the usage.

That is do you need it for doing something like PWM output? If so maybe you can directly use PWM.

If you need timer interrupts of some specific timing, maybe IntervalTimer might work or maybe @Luni's timer tool:
There is some write up about different timers up in his WIKI for that tool: https://github.com/luni64/TeensyTimerTool/wiki

Else I often look at datasheet and searching through the Teensy install. To see other places that maybe use TMR4, or maybe IMXRT_TMR4.
And find it is used in the core file pwm.c, also used in the ADC Library, also in FreqCount, PulsePosition and maybe a few other libraries.

But again not sure if that would help.
 
I agree, understanding the usage is important. Looking at the Marlin timer code for the MK64FX512 and MK66FX1M0, it looks like they are defining 2 16 bit timers. So I would figure out how to set up 2 16 bit timers on the 1062. However, I'm pretty sure that Marlin uses PWM in places so I would look to figure out if the timers were involved in that as it might change which timers I would use and how I'd use them.
 
The timers I am mostly interested in are the ones used to generate the step pulses for the stepper motors.

I just did some simple tests and with the insane speeds of the Teensy4.0 I'm thinking maybe hardware timers are complete overkill?
Or are there other benefits to hardware timers that I don't see?
 
To see if I could go without the complicated hardware timers, I ran a test ramping up a stepper to 100us period step speeds and this worked absolutely fine without using hardware interrupts.

One strange I thing I noticed: if I break the serial USB connection my timing seems to go wrong completely..

Here's a minimal example of the serial issue, tested on Teensy4.0 :
Code:
uint32_t lastTime = micros(); // keep track of time for LED blinking
uint32_t period = 100;

int timingError = 0;

uint32_t serialLastTime = millis(); // keep track of time for serial feedback
uint32_t serialPeriod = 200;

//---------------------------------------------------------------------------------------------------------------------
void setup() {

  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);

  while (!Serial) {
    // wait for serial to come up
  }

  Serial.begin(57600);
  Serial.println(
      "I am testing if serial connect / disconnect messes up my timing");

  serialLastTime = millis();
  lastTime = micros();
}

//---------------------------------------------------------------------------------------------------------------------
void loop() {
  uint32_t nowUs = micros();
  if (nowUs >= lastTime + period) {
    timingError += abs((int)(nowUs - lastTime) - (int)period);
    lastTime += period;

    // briefly flash the LED
    digitalWrite(LED_BUILTIN, HIGH);
    delayMicroseconds((int)period / 2);
    digitalWrite(LED_BUILTIN, LOW);
  }

  uint32_t now = millis();
  if (now >= serialLastTime + serialPeriod && Serial) {
    //   if (now >= serialLastTime + serialPeriod ) { 
    //  creates visible pulses with LED staying OFF

    serialLastTime = now;
    Serial.println(timingError);
    timingError = 0; // reset timing error
  }
}

This will print out zeroes every 100ms, except when I disconnect and reconnect the Serial port..

The version where I keep sending serial messages even when there's no serial port is significantly worse:
Code:
if (now >= serialLastTime + serialPeriod ) {
instead of
Code:
if (now >= serialLastTime + serialPeriod && Serial) {

What could be going on?
 
The timers I am mostly interested in are the ones used to generate the step pulses for the stepper motors.

I just did some simple tests and with the insane speeds of the Teensy4.0 I'm thinking maybe hardware timers are complete overkill?
Or are there other benefits to hardware timers that I don't see?

In that case another contribution by @luni may offer a solution: github.com/luni64/TeensyStep
 
YES!
I might have not discovered anything new here, but at least i proved it to myself :)

Timing errors while connecting and disconnecting the serial port without Serial.availableForWrite():
Screenshot 2020-08-02 at 12.54.29.png

and with
Code:
if (now >= serialLastTime + serialPeriod && Serial.availableForWrite() > 8) {
Screenshot 2020-08-02 at 12.55.43.png

The difference is huge, but as you can see there are still tiny errors. I wonder where they come from?
 
Any chance you could explain how to run this test?

What are those plots? Are they from a logic analyzer or USB oscilloscope? Is that the voltage on pin 13? Or are you collecting data somehow and plotting it with specific software?

And could you give the latest code, so I can just copy the whole thing into Arduino and run it here on a Teensy 4.0 without the error-prone process of splicing in the changes.
 
Hi Paul I love your work! :)

The plot is just some test software I use to debug. It plots out values sent over serial similar to the Arduino IDE's "Serial Plotter" but without the annoying rescaling. I have some more interesting display options, auto-connecting and other things I need for debugging and analysing code.
I didn't hook this up to my scope yet.

So what you see is literally zeros sent over the serial USB, peaks are higher numbers.

This is the code with the addition of Serial.availableForWrite:
The original line is still there, I just commented it out.

Code:
uint32_t lastTime = micros(); // keep track of time for LED blinking
uint32_t period = 100;

int timingError = 0;

uint32_t serialLastTime = millis(); // keep track of time for serial feedback
uint32_t serialPeriod = 200;

//---------------------------------------------------------------------------------------------------------------------
void setup() {

  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);

  while (!Serial) {
    // wait for serial to come up
  }

  Serial.begin(57600);
  Serial.println(
      "I am testing if serial connect / disconnect messes up my timing");

  serialLastTime = millis();
  lastTime = micros();
}

//---------------------------------------------------------------------------------------------------------------------
void loop() {
  uint32_t nowUs = micros();
  if (nowUs >= lastTime + period) {
    timingError += abs((int)(nowUs - lastTime) - (int)period);
    lastTime += period;

    // briefly flash the LED
    digitalWrite(LED_BUILTIN, HIGH);
    delayMicroseconds((int)period / 2);
    digitalWrite(LED_BUILTIN, LOW);
  }

  uint32_t now = millis();
  // if (now >= serialLastTime + serialPeriod) { // <<< original line
  if (now >= serialLastTime + serialPeriod &&
      Serial.availableForWrite() > 8) { 

    serialLastTime = now;
    Serial.println(timingError);
    timingError = 0; // reset timing error
  }
}
 
Just to be 100% sure I'm still following you, you're goal is to make changes to Marlin's timer HAL code to get it to run on the iMXRT1062. Software timing relies on all the other code behaving. Even in your little test program, there is other software involved. With a hardware timer you get an interrupt asserted exactly when you asked for it. As long as the rest of the code behaves with respect to interrupt disabling/enabling (which I am sure the rest of Marlin 2.0 does), a HW timer will get more consistent results. Inconsistent step pulses will give you positioning or extrusion errors, depending on which stepper motor it's for. They may be small but I have no way of knowing that.

That said, I don't see how you would use SW timing in the HAL code. It expects an interrupt to be generated at a specific time.

If it is, as you said, only for step pulse generation then it shouldn't be that hard and you have example code in a number of places to draw from.
 
If the board gives you a hardware timer, use it. In the future, you are probably going to add some code that does something or other, it's going to nudge the timing a little, and your software interrupt is going to be late sending a pulse. That's no bueno. Even if it only happens occasionally, consider what even a few dozen missed steps can do to a 15-hour print. Layers getting squished or shifted, etc.

You probably have good reasons to port Marlin. If it was me, I would look at Repetier or Smoothie. Both ran better for me. Smoothie's codebase can tell you some things about generating steps on ARM, since it was designed from the ground up for 32-bit ARM controllers. The codebase is (in my opinion) laid out better as well. It also gives you a (not very fancy) working web UI for uploading G-code, moving the effector around, etc.
 
Sorry for in advance off topic question:

As I mentioned about a year ago in another thread (https://forum.pjrc.com/threads/5656...rd-USB-connector-torn-off?highlight=printrbot) I have a printrbot Metal 3d printer with a Printrboard Rev F5, which the USB connector broke off. Printrbot has folded and UBIS was selling a new board for it a year ago, but I no longer see it listed on their website.

Any recommendations for a replacement board? Would be great if Teensy based. Preferable one that is mostly if not fully populated.

Thanks,

Kurt
 
Any recommendations for a replacement board? Would be great if Teensy based. Preferable one that is mostly if not fully populated.
Smoothie or Duet if you just want to get down to business and print some things.

If you want a ~Project~ to keep your hands busy, it's right here in this thread. :)
 
It looks like there is a Marlin port for the T3.5 and T3.6. The timer code TimK linked to has ifdefs for both. The iMXRT1062 is overkill and I bet the T3.5 and T3.6 are too. I've thought about making a 3DP breakout board for Marlin/T4.x though there are plenty of solutions already out there. Still, watching this thread hoping someone might move the ball towards the goal.
 
Hello guys nice being here, I am from France and we, some of the Open PnP community and I, are actually having a work in progress, the PeeNaPle_V1.1,
a breadboard for Teensy4.1 Open PnP oriented! So I am gathering informations here and there to make it happen. the board is almost done, stuck with
the pin designation, there seem to be various possibilities depending on how you use the MXP! Here is a little snick Pict, we would love to have either Marlin
or GrblHAL running on this board at full potential If you have any suggestion feel free to let me know, and one point to precise I am a very New B in coding
more of a pcb designer, so please bear patience if you can! with that said , going back to kicad, to send board to PCBA! Cheers!
Screenshot 2020-08-11 at 23.12.35.jpg
 
Looks like you have support for 8 axes, which is... absolutely wonderful. :)

What PCB house do you like to produce your boards? I have used Seeed in the past for a few things. Good quality, but the allowed parts can be limiting.
 
Status
Not open for further replies.
Back
Top