-
-
Notifications
You must be signed in to change notification settings - Fork 19.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Marlin2.0 LPC1768 Software Serial(UART) for TMC2208, it seems to work fine #13197
Comments
Hi I've also been working on exactly this. I've just got things working and can also run using any pin my only extra requirement is the use of the RIT interrupt. I'd be interested to see your implementation. What baud rates have you tested? Have you run into any issues with jitter when printing due to the time taken by the various Marlin interrupt routines? What parts of Marlin did you need to change? My intention was to only need to changes to the SoftwareSerial files (though I ,may also change the baud rate used by the TMC code). |
open file |
Yes I'm very familiar with that code, but it requires pins that generate a software interrupt on change for the receive line. Have you made other changes? |
Yes, I also add some functions in this file and changed the TMC2208Stepper.cpp file line 94 uint32_t TMC2208Stepper::read(uint8_t addr), In order to make the pins without interruption function can also be used as RX, there is a little change in the Arduino framework. I think this is not good, so we need to discuss it. I will update the change to github tomorrow, and let you know |
OK, I hope to be able to start testing my solution with a TMC2208 later today. So far I've been testing with a terminal connection and a scope to check on timings etc. Have you had the code that checks the 2208 temperatures during operation (MONITOR_DRIVER_STATUS in Configuration_adv) running? I had a look at the stepper code timing and it looked like that could cause problems for timing of read and write operations when using software serial. Looking forward to seeing your solution. |
Thanks! Will give your version a test and see how I get on. It is much simpler than what I've been doing (which is good!). |
What board are you guys testing with ? Following this with interest. |
I tested it with BIGTREE SKR V1.3 |
@Msq001 please submit a PR against bugfix 2.0 |
i personaly can use this and will use with re-arm+ramps 1.4SB |
@boelle Hello, I changed the library file, SoftwareSerial.cpp of lpc1768 and TMC2208Stepper.cpp , Did not change the marlin source file,So, I can't create a PR for marlin , https://github.com/Msq001/marlin_2.0_bugfix_tmc2208. You can download this project to test |
Skr v1.3.? v1.2 isn’t available yet. |
@PeteBurgess skr v1.2 is a debug version, v1.3 is testing now, and will be released soon. if you have a motherboard with LPC1768, add software series pins to the <pins_board_name.h> file and you can use this project. |
@Msq001 I recommend rather than simply uploading the files, you fork Marlin/TMCStepper/whatever. It's way easier to see the changes and allows you to actually make pull requests. |
https://github.com/teemuatlut/TMCStepper/pull/13 @teemuatlut hi~ here is the files have changed |
@Msq001 i think he meant to fork marlin git and not his own git |
OK So I now have some results from testing this approach and from some further tests on an alternative that uses the RIT timer to generate and read the software serial signals. Before I give the results let me explain the tests I've been using and the types of error I'm trying to detect... When you talk to a TMC2208 commands are sent to the driver using short 4 byte packets and responses are received as an 8 byte packet. In both cases the packets contain a single byte checksum. The majority of commands do not have a response (as they are used to set values). If the checksum of the command is not correct the command will simply be discarded by the TMC2208. This raises the obvious question of how do we know if there is a problem when we send a command? The long answer is that the TMC2208 does provide a mechanism (using sequence numbers), that will allow you to detect if a command has worked, but this is not used by the current TMC library. So the short answer is that at the moment there is no easy way to test commands that do not send a response back to the control board. However it is possible to use commands that get a response to detect both send and receive errors. Receive errors are easy we simply compute the checksum on the data we get back and if it does not match there has been an error. But what about if there is an error writing the command to the TMC2208? Well in this case the device will simply ignore the command and with the current code we will read a response that is all zeros. Unfortunately the checksum checking code will not identify this as an error (as the checksum of all zeros is zero), however no valid response is ever all zero (as it must have a special start byte ) so we can detect the all zero case. So write errors will show up as an all zero response and read errors as a checksum. As I said above the majority of commands (used to set values) do not generate a response from the TMC2208 so it is not easy to use these for testing purposes. However if we enable the MONITOR_DRIVER_STATUS option this will read the status registers on a frequent basis and so can be used to test both command and response handling (since a read request sends a command and reads the response). Unfortunately by default the TMC code does not monitor the status of drivers using software serial, nor does it check the response either for a bad checksum or a zero packet (the checksum is computed, and errors are noted, but nothing ever checks the error flag). But these problems are easy to fix by small modifications to the TMC library. OK so the test setup is one in which we have the modified TMC library that has status monitoring of the device enabled and that has extra code to count the number of CRC (receive errors) and zero responses (write errors). I have a test board (SKR V1.1) with two TMC2208 devices (and 2 TMC2130s but we can ignore them). The test consists of three parts. Part one is simply to power the board on (which initialises the devices) and note any errors detected during this process. Test two is to leave the board idle for two minutes (during which the status of the devices will be tested repeatedly), test three is to run a 30 minute test gcode file. At the end we report the detected errors from each test. So here are the results obtained using the modified SoftwareSerial class running at 115200 baud using polling for receiving data. The results are given as read errors/write errors for each test.
Obviously we need to dig a little deeper. See next post |
Ok so those results do not look very good, interestingly we have a lot of read errors but zero write errors. So what is going on. We need to understand what is causing the errors and it is all about timing. Basically we are are generating the serial pulse train by timing the gaps between the various on/off states of the pins. Similarly when we are receiving a byte we are sampling the state of the pins then waiting a fixed time and sampling again. Just to understand the scale of things at 115200 baud we have a gap between the pulses that represent the data of about 8uS. Now computers are reasonably good at timing things at this sort of scale so what is going wrong? Basically interrupts. These are used in Marlin to do things like generate the stepper pulses, check temperatures, handle serial and USB I/O etc. The thing is an interrupt is a bit of a bully and will push other code out of the way when it needs to run, in this case the code that is being pushed out of the way is our receive loop and its associated timing code. Imagine what happens to our code that is sampling the data every 8uS if along comes a pulse generation interrupt that can run for up to 10uS! Yep that is exactly what can happen. Given that these interrupts can occur every 20uS it is a wonder that we manage to get any good data at all. Now you may be wondering why we are not getting any write errors, surely the interrupt issue should be screwing up our output pulse generation just as much? Well yes it should except that our write code has a secret weapon, it disables interrupts when generating the pulses for each 8 bit character (which is actually 10 bits long because of start and stop bits). This means that the timing for the pulses is actually pretty good with no "jitter" due to those pesky interrupts. So can we turn off interrupts when receiving data? Well Yes we can and when we do we get the following results....
Which is clearly much better, but why are we still getting read errors. Well we are only turning interrupts of for each 8 bit character, we enable them between each one. This is OK on the write side of things as it doesn't matter how big the gap is between each byte (well not that much). However on the read side we don't control when the bits arrive and if our sampling code is not there ready to go when the first bit of a byte arrives, well we miss it. So simple we just leave the interrupts off until we have all of the 8 bytes we need? Unfortunately those steppers are not going to be running very smoothly if we stop feeding them pulses for 8108uS (8 characters 10 bits per character 8uS per bit) so 640uS. In fact turning interrupts off for 80uS is probably pushing our luck a little. So what else can we try? |
We already use advanced tricks to no miss any of the hardware serials rx-interrupts. The trick how to Address Multiple Slaves with a single serial is described in chapter 4.4 (page 21) of the datasheet. The pins for setting the gates are by far less demanding, don't need to create interrupts, don't have to be on an U(S)ART, could be any output pins. |
I have several boards sitting here with direct wire connection for 2208 UART. If you gentlemen don’t mind me snagging a zip of your modified Marlin, I would be more than happy to test. |
@AnHardt Yes I agree that a hardware serial solution (possibly with extra switching hardware) is the best way to go. I wonder if anyone would be interested in a hardware add-on that would do the multiplexing? But it's still an interesting challenge to see what you can actually get out of the hardware you already have, without making hardware changes. Especially if like me you are a software sort of guy! So I'm going to continue to investigate further. Of course if I was a board manufacturer (or someone testing a prototype board) I would definitely be pushing to have that hardware solution added to the board! At the end of the day any software hack is likely not to be 100% perfect and may impact print quality (see my point above about disabling interrupts). I think a simple polled SoftwareSerial implementation (with interrupts turned off during send/receive), is good enough for performing TMC2208 UART based configuration. But it probably is not a good idea to use this approach for monitoring the drivers or talking to them at all during printing. You can probably use that solution on pretty much any board that has pins available (well 32 bit boards anyway). It's a bit of a hack, a little like using the enable pins as chip select lines for TMC2130 drivers with the SKR V1.1 board, but some people may be happy to have that. For now I'm still digging that hole trying to get better software monitoring of the drivers. |
Continuing on in my investigations and testing. So far we have been running the SoftwareSerial UART at 115200 baud, now that's nice, but it does impose some pretty tight timing requirements (for software at least, even on a 32bit board). At the moment we need to be able to measure reasonably accurately delays of around 8uS or so and we are operating in an environment that has a pulse generating interrupt that can in some circumstances take 10uS or so. This is not a good combination. So an obvious solution is to relax some of the constraints in this case the baud rate. A lower baud rate will make the timing far less critical if we drop the speed to say 38400 we now have a pulse length of around 26uS which is somewhat more manageable and we may even be able. Pushing a little further we really only have a few bytes to move around, so why not drop the speed down towards the minimum speed that the drivers support (9000bps), so 9600 baud. This it turns out is the speed used by Klipper for these devices, so it seems to work fine (at least for configuration). With that our pulse timing goes up to a very manageable 104uS. But with this length of pulse we really can't continue to disable interrupts (arguably we never should have). So what do the numbers look like with these configurations?
As we can see no longer disabling interrupts mean that we are now getting write errors but the slower speeds clearly help with the timing. Out of interest I did test with the ints disabled and the steppers basically stopped working! Oh and just in case you are wondering all of these tests actually perform the same number of checks on the drivers (the poll routine always runs for the same period). |
So the final thing I've taken a look at with this polling approach is how the delays are generated. The code in the LPC176X framework creates some very accurate delays, but these delays are based on executing code that takes a certain number of cycles to run. This code is then executed a number of times based upon the desired delay and the speed of the cpu. But what happens if part way through delay of say 104uS there is an interrupt that takes 10uS? Well you end up with a delay of 114uS (or so). Now it turns out that this can mess with some of our timing. So replacing the delay routines with one that uses one of the hardware timers can have interesting results:
As you can see correcting the timing to allow for any interrupts helps a lot (final two results above), lowering the error rate pretty much to zero when running at 9600 baud. |
@gloomyandy I was considering using a coprocessor like the STM32F030K6T6 or STM32F103C8T6 to handle all of the UART setup and monitoring for the drivers. There should be enough IO’s to handle the process for plenty of drivers and I think that the M3 processor of the F103 would be easily up to the task. It would take a lot of load off processors such as this and reduce the pin count to ideally a single hardware UART connection back to the main CPU that reports back if the driver throws an error, etc. I have no problem handling the hardware aspect but I cannot handle any of the software. |
@Msq001 I flashed your code and do not have RX errors anymore but I am getting command not recognized when I try a M911. Current to drivers do not seem to change either whereas I could definitely note a holding torque change when using the current bug fix version. |
@gloomyandy With regard to MONITOR_DRIVER_STATUS when printing, I intend to replace both RX and TX in the interrupt of the timer instead of using delay_us, and I am working on that now. I think it would be much better. The only disadvantage is that it takes up extra timer. If there's any progress, I'll let you know in the first time |
@griffin-117 hi~ Have you tried M906 command? I can change the current with M906 command. |
@Msq001 you may want to wait a couple of days and take a look at the code I'm working on. It uses the RIT interrupt for timing and also only needs a single I/O pin per TMC2208. I have it working reasonably well at the moment but want to clear up a few things. It does not require any polling for the I/O. |
@gloomyandy so, I think I get it now, but can you summarize the state of 2208 support on SKR 1.1, for those of us who don't speak code? 😉 |
There is a new SoftwareSerial implementation for LPC1768 based boards. This new version can operate with TMC2208 drivers using just a single pin per driver and that pin does not need to be interrupt capable. The driver should also work with the TMC2208 in two pin mode, but this has not been tested. The new driver is now included as part of the LPC1768 framework and so should "just work" if you configure Marlin to use it, no special version of the TMC libs are required. Some additional notes:
|
@gloomyandy Ok. I've updated Marlin to commit 2513f6b, and the soft serial library is already at 0.1.0... using single-wire connections, with your previously-mentioned pins definition (wrapped in M122 output>>> m122 SENDING:M122 X Y Z E Enabled false false false false Set current 600 600 800 400 RMS current 581 581 795 397 MAX current 819 819 1121 560 Run current 18/31 18/31 25/31 12/31 Hold current 9/31 9/31 12/31 6/31 CS actual 9/31 9/31 12/31 6/31 PWM scale 33 11 14 7 vsense 1=.18 1=.18 1=.18 1=.18 stealthChop true true true true msteps 16 16 16 16 tstep max max max max pwm threshold 0 0 0 0 [mm/s] - - - - OT prewarn false false false false off time 3 3 3 0 blank time 24 24 24 24 hysteresis -end -1 -1 -1 -1 -start 1 1 1 1 Stallguard thrs DRVSTATUS X Y Z E stst X X X X olb ola s2gb s2ga otpw ot 157C 150C 143C 120C s2vsa s2vsb Driver registers: X 0xC0:09:00:00 Y 0xC0:09:00:00 Z 0xC0:0C:00:00 E 0xC0:06:00:00 Testing X connection... OK Testing Y connection... OK Testing Z connection... OK Testing E connection... OK However, the motors won't move in Did I miss a step? Configs: Marlin-configs-32bit-20190304-2.zip |
You have SOFTWARE_DRIVER_ENABLE set, unless you have added a wire from the driver enable pin to ground (and disconnected the pin that goes to the board connector) I suspect that may cause problems. I've also not tried that mode of operation with TMC2208 drivers. I would also be tempted to set the current to at least 800mA to begin with and reduce it once you have things working. I would also enable MONITOR_DRIVER_STATUS when you have things working as it provides very useful information about driver temps. By default you will be operating with 1/8th microstepping I think. Oh and and on this board you may run into problems using LIN_ADVANCE it seems to mess up the pulse timing. You may need to set a MINIMUM_STEPPER_PULSE value of 1 or more. Search the issues for details of why. |
Now unset, set, and set, respectively. This got me going, thanks! Now I can actually test stuff. 😃 Oh, as for currents, those values are from earlier use of my 2208's on an Arduino/RAMPS stack, and are already mostly appropriate for my hardware. Had to turn the E current up a bit from there, though. |
Are you using 12V or 24V? If 24V you may want to change CHOPPER_TIMING as well. Lots of folks seem to have to run E steppers in spreadCycle mode (especially with linear advance), but I guess that is all down to fine tuning. |
I'm using a 12v system. I looked at that setting a while back and couldn't make sense of it. Interesting.... I have to run E in spreadCycle mode also (it's not apparent from my config, but it's "forced" by fast retracts that exceed the hybrid threshold). |
Initial impressions after a couple of test/calibration objects and a small wade's gear that I've been needing to print: It's working really well for me. Short and sweet 😃 There is one thing that I think should be addressed, but it's not specific to the 2208 (rather, to all TMCs I guess): if accelerating/decelerating during a move would cross the stealthChop/spreadCycle hybrid threshold, find some way to avoid confusing the TMC's math -- they get noisy when close to the threshold because of double/quad stepping. Maybe split the accel/decel periods into many short moves and let the TMC driver itself handle them, instead of banging on step/dir? |
@VanessaE Good to hear that it is working. Thanks for trying it. As to your comment about the acceleration/deceleration and TMC driver, you may want to create a new issue and explain the problem and possible solution there. I'm not at all familiar with that side of how the drivers function, I'm sure @teemuatlut and others could comment, but I'd rather keep this thread focused on the software UART if we can. |
Fair enough. Comment moved to a new issue. (#13316) |
Can we get the pins definitions in @gloomyandy's post (step 4) officially added to |
I intend to create a PR for this (there needs to be an alternative for when using a TFT screen, which I'd really like to test before creating the PR). There are other changes also needed to finish this off completely. Like for instance you will not be running the monitoring code unless you have modified tmc_util to remove the requirement for a hardware UART. There are also changes needed to make the baud rate more suitable for use with this modification (at the moment there is a hack in the framework code to do this). If all goes well I hope to get to this later this week. |
agreed, |
@gloomyandy Nice work :) Is this change of SoftwareSerial library usable also for 8bit microcontrollers (Atmega2560)? Because FYSETC F6 1.3 board has problem with RX pins without PCINT #12800 (comment). Thank you :) |
Probably not and certainly not without re-implementation. This code is really LPC176x specific. |
Hi!! is this 1 pin serial sullution inplemented in the latest 2.0 builds u can download? or do i need to use the serial files from u @gloomyandy Bulding a new 3dprinter with Sbase 1.3 with the lc1768 chip and TMC2208 drivers.. best regards Jan // Sweden |
At least on Re-ARM it looks like it's implemented - the pins.h file for Re-ARM shows the same pin being used for TX and RX. |
hmm... weerd... its the same lpc1768 chip on both re-arm and my mks sbase it should work... wonder whats the difference between the 2 cards sowftware wise,... |
This should work fine on the sbase board (that's what I originally developed it on!). What exactly are you trying to do and what pins on the Sbase are you trying to use for the software serial interface? What makes you think it is not working? I assume you are trying to talk to a TMC device, which one? Are you sure you have the driver modules configured correctly? Also the Sbase 1.3 has onboard drivers so are you not using them? |
Hi and thnks for anwsering. So when u say half duplex comms is it just Write or Read depending on the resistore or is it Both on a single wire on the sbase? Should i just re config the sbase/pins.h so that both RX/tx is on the same pins? Is there som pins that is better to use for the serial com to the drivers? Best regads Janne |
Whitch ones do u recomend? have 5 tmc2208 Have a double Z steppers.. or shoud i scrap 1 driver and just go Y-Harnes on 1 Z driver To 2 pcs of z stepper motors and ramp up the current on that driver? |
It does read/write on the same pin. You just need to define both the RX and TX pins to be the same pin. I'd use 5 pins on the J8 connector so.. #define X_SERIAL_TX_PIN P1_22 // J8-2
#define X_SERIAL_RX_PIN P1_22
#define Y_SERIAL_TX_PIN P1_23 // J8-3
#define Y_SERIAL_RX_PIN P1_23
#define Z_SERIAL_TX_PIN P2_12 // J8-4
#define Z_SERIAL_RX_PIN P2_12
#define E0_SERIAL_TX_PIN P4_28 // J8-6
#define E0_SERIAL_RX_PIN P4_28 Note I've not tested this! If you want to use E1/Z2 then you will need to find another suitable pin. You could use pin P0_02 or P0_03 if you are not planning on using the UART interface to talk to any sort of touch screen. I'd avoid trying to use the endstop/thermistor pins if you possibly can as they will have extra pullups etc. on them that may cause problems. |
ok... thanks alot... =) will put this in my fW and have a go on the test bench =) |
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
I have modified the firmware for the TMC2208 UART and LPC1768 software serial lib sections, Now it's not necessary to use interrupt IO for RX, Does anyone want to test it? I can send you the complete project.
The text was updated successfully, but these errors were encountered: