An Electronic Lead Screw controller using a Teensy 4.1

What I often do in cases like this is increment an error count and keep going. One error in a while is not a good reason for a real time system to quit, if it can keep going. We just want to know it happened and see how often and what it correlates with. My Pico GPS program makes one counted error during startup and then never does again, so I can decide whether that is worth fixing or just ignore it. Reminds me of an old 4 stroke outboard motor that would quit if the oil got low as an equipment protection feature. The newer version of that same motor would sound a buzzer and keep going. It should be up to the captain to decide when to shut the motor down, he just needs to be given the information. Maybe avoiding the rocks is worth risking engine damage. If the ELS misses a count now and then the threads are still likely to make spec. During feeding it matters even less. Quitting on error will probably ruin the threads or make surface defects in the feed.

Stepper motors can usually go much faster than they can cold-start. It's often shown in motor performance graphs. Deciding the max RPM based on available torque is probably more useful than cold-start RPM, but that's a choice. The spindle will slow the ramping up to speed.

Graphical displays eat a lot of cycles and time, I've had many issues with that. Having a second core could help. On the Arduino I didn't have a second core so the display code had to be partitioned into many smaller updates so they could be interleaved with the critical ops. USB activity, or network activity can also make big holes in interrupt latency. Interrupts aren't always the best or simplest solution. It is very hard to know the maximum time the interrupts get disabled in a sea of libraries. And it may change with the next update.

Printing when there are errors in a real time system often causes cascades of more errors. Printing is very expensive and disruptive to the real time system. Sometimes we have to write our own simpler printing routines to get better control over things like max interrupt latency. Many libraries just disable interrupts way too long. Most programmers don't understand real time so they don't write libraries to support it properly.

Can you do smaller TFT writes, or is it buffering and rewriting the whole display?
 
Seems like I need a more elegant count missing routine. One that handles errors better. I think the hw counter should be ok, but my loop isn't executing fast enough when the display is active. So maybe I am missing the count, but actually the HW counter is correct. I can add some additional processing to fix that and add an error counter to watch that the process is under control.

I've dealt with real time development before, but lacking ICE and breaks does make the process a lot harder. I've resorted to pin toggling to check for the long poles in the tent, so I can do this again.

So far have only written characters to the display, haven't done anything fancy save for writing black to a box containing the old text so it can be re-written with new text. I've done this before to avoid garbled text. Apparently on this Teensy library these actions are blocking and costly in execution time. They may also disable interrupts for all I know. I thought they used DMA and SPI for this. Honestly, I'm surprised that only writing the RPM (5 characters maximum) is causing a problem. Think it is more likely that it's the erasure that blocks. Obviously need to dig into it further.

I will ask on the PJRC forum for some tips to get the most out of the display. Worst case, I'll consider a different solution, anywhere from changing processor to adding a display processor. First is to see if there's more clever ways to do what needs to be done.

The whole display only needs a 250-500 ms update rate, so this shouldn't be too hard. Just writing that makes me realize that I was writing to the display faster than that. So I'll go fix that first!
 
Sounds like you are on the right track. For something like RPM I would probably write a fixed width text block and avoid the erase. Writing to the display too often could certainly be an issue. Even if they use DMA they probably have to disable interrupts during setup and of course during interrupt handling. One inappropriate call during an interrupt handler can bring a system to it's knees. Sometimes it is hard to know which calls are incompatible. 2500 rpm times 4096 edges is 170,000 interrupts per second (just for the encoder counts, not including all the other timers, etc) which is a fairly high interrupt rate. Systems are usually designed to avoid such high interrupt rates.
 
Last edited:
Plugging away at this. Received some good hints on PJRC forum, so I am pursuing them.

Got a bit frustrated with the setup on my desk, so yesterday built up a consolidated driver/receiver board to reduce the clutter on the desk. Of note, is that I originally used some 1.15K resistors for the encoder pull ups. I had a bag of them, and couldn't think of a future use of the weird value, so I used them. Bad idea. I got false triggering due to the slow rise times. The counts were dithering about +- 1 count, but I was spinning the encoder a lot in the forward direction. The original breadboard and the new board had the same circuit. Only difference was the pull up values. Had to rework the board this morning to put in 330 ohm resistors. No more false errors in no display mode.
 
Good to know. So you are using 330 pullups to 3.3V on the open collector outputs of the encoder, and 5V to power the encoder logic?
 
Good to know. So you are using 330 pullups to 3.3V on the open collector outputs of the encoder, and 5V to power the encoder logic?
Actually I am powering the encoder with 5V and pulling up to 5V. I use a 74LVT245 powered with 3.3V to convert the 5V (tolerant to 5V) signal to 3.3V which is then connected to the Teensy 4.1. Teensy 4.1 is not 5V tolerant. Yes, I could have skipped the buffer, but chose not to, since I don't know how the wiring is going to end up. This way, if need be, the bus driver can drive a long distance.
PXL_20220515_133141069.jpg
 
A bit more progress. Found a different software encoder library that lets me embed the Bresenham algorithm upon detection of the count changing. So I stuffed Bresenham into the callback. It in turn sets off a one shot timer to pulse the stepper (if required) and then exits the callback. Much better behavior. Curiously, the library using the HW encoder and the software encoder library disagree with direction. Someone must have flipped the A phase with the B phase... Not a big deal, but was quite a surprise to see the stepper move opposite to the encoder!

Now, if I put in a write to the tft display, or even a delay in loop, nothing bad happens, ie, things keep humming away. So now I have a live estimate of the RPM on the tft display. With a brisk hand snap of the encoder shaft, the program has kept up to 1200 RPM and moved the stepper and updated the tft display (an ILI9341). It doesn't look like much, but this was a big step forward. So now I can think about user interface stuff. As well as setting things up for feeding.
 
Good Progress.

Encoders are like motors, half the time they go the wrong way. :)
 
Last edited:
Does anyone have experience with controlling stepper motor drivers via RS232? I have seen some drivers that have RJ45 jacks that say RS232 on them. I have seen this on some SteppersOnline drivers. They offer some old ghastly software from 2013 windows only to program some of the parameters. The only parameter I'd really like to control right now is the microsteps. I don't often use windows. Do you know if the ICD is available? Looking for baud rates, start, stop bits, etc. Is the interface actually RS232 levels or just 0-5V? There should be a list of the commands and the expected responses? I can setup a serial port and then I'd be able to control the driver better. Flipping dip switches should have died in the 1980's.
 
Back
Top