Explanation: How the M2 Nano Works?

For MeerK40t I’ve done pretty extensive reverse engineering of the M2 Nano. I’ve also noticed a number of comments about board that are wrong. These tend to not understand the fundamental difference between an M2 Nano and some entire-computer-on-a-board cards. So I’ve done my due diligence to explain this in a 10 minute video.

If you have any comments or question or if anything is confusing I’d be happy to use that to improve the video.


Thanks for making that!

I couldn’t quite make out in the video: is the third chip to the right of the processor program memory for the program that interprets the bytestream?

I updated the video since I had glossed over that. the 3rd chip is a HC14, a Hex Schmitt-Trigger Inverter. Basically cleans up the switches for the on and off edges for the laser. The updated video takes a bit of time to explain that a bit.

0:37 - 0:47. It’s basically the laser chip.


There is no memory. A couple bytes in the processor, but that’s it. The entire rig doesn’t do math and doesn’t have memory. Damn thing doesn’t even have an eeprom to store a serial number. The only thing that’s even slightly unique or identifying is that the CH341A/B tends to have a version number which can be requested and differs from board to board a lot depending on the run. I also corrected where I called the CH341A a serial chip, its really a universal USB interface chip and runs in Parallel mode for the M2 Nano specifically EPP 1.9.

The 8051 tends to have up to, I think, 4k firmware space which is where the interpretation code would be. I’ve sort of wanted to cap one of those chips and dump that firmware. There’s also that section where it clearly has some lineouts from the processor go to the active pins.

Also for a kinda unknown reason the X stepper chip has a R470 resister and the Y-stepper chip has a R360 resistor. The guess was that the bar moving for the Y needs more oomph.

Datasheets for all the primary chips (has 2 A4988s)
CH341: http://www.wch-ic.com/products/CH341.html
8051 Processor: http://ww1.microchip.com/downloads/en/devicedoc/doc4383.pdf
HC14 Schmitt Trigger: https://www.ti.com/lit/ds/symlink/sn74hc14.pdf?ts=1595840021355
A4988 Stepper Chip: https://www.allegromicro.com/-/media/files/datasheets/a4988-datasheet.ashx


That bytestream could certainly be interpreted in 4K of program!

I assume the R470 and R360 resistors are each one half of a voltage divider to provide a reference voltage then?

Nice knowing how hard it is to reverse engineer something [the laser power supply] I know how much work went into this … nice job!


In some of the more paper-based documentation, that was looked into. It’s actually true they run differently.

“The chips are configured in 1/16th step mode by holding MS1, MS2, and MS3 (A4988 pins 9, 10, 11) high from a combined trace on the PCB. Both X and Y axis drivers share the same 0.70 Volt REF input trace on the circuit board (routed to A4988 pins 17); but the individual chips are connected to different value sense resistors. The X axis uses R470 (0.47 Ω), and Y axis R360 (0.36 Ω) sense resistors. That drives the X axis motor at 0.44A per phase, and the Y axis motor 0.33A per phase.”

Joe Lane who helped with the main work there had blown out his Y-axis chip and replaced it better set of chips, that run silently and have more bells and whistles than the A4988s. So it was a bit of an oddity that was worth documenting. But, the most interesting stuff is how it runs basically in bytecode and that doing that with an arduino which currently couldn’t possibly run gcode at a good enough clip could absolutely run 3d printers, embroidery machines, lasers, vinyl cutters, and a lot of kind heftier stuff. Especially if the scheme was generalized. It wouldn’t be hard to add a few extra axises and some PWM stuff, without ballooning the code.

1 Like

Oh, I was confused. I had the schematic representation I’ve seen where R is used instead of Ω but of course you were referencing the surface mount resistor code. I feel silly.

This is basically what Klipper does, though I’ve never looked into details of its bytestream. Marlin just added G6 External Motion Controller in the 2.0.6 release a couple days ago. So I guess great minds think alike?

Hm. I likely will look into the specifics there, since really hooking into something already established would help with various goals. If the code works well it wouldn’t be too hard to support it for lasers. But, I’ll just mostly backburner it. It’s certainly a great scheme.


So will there be aMeerK40t for an Arduino?

I think that the question starts with “will there be an Arduino sketch that implements the lhymicro-gl language?” There’s a python implementation of it in LhystudiosDevice.py in meerk40t to learn from. It feels to me like “1000 lines of code” (more than 100, fewer than 10,000) to implement this language on Arduino, where you would have a much larger buffer to avoid stuttering. You can start reading it from the EgvParser:parse() method followed by parse_egv if you are interested. (Obviously @Tatarize can give a better answer, that’s just what makes sense to be breezing through it.)

After the relatively easy task of parsing the language, I’d think that getting the speed codes right would be the primary challenge for faithfully implementing the lhymicro-gl language on an arduino, since it looks like their interpretation isn’t 100% clearly understood, looking at LaserSpeed.py:get_acceleration_for_speed(). Getting the frequencies and divisors set up to mimic the configuration on the 8051 could well be the trickiest part.

This would probably fit on the attiny84 but I’d be worried about it working with softusb; I’d think you would still want a USB interface chip rather than using softusb. Just like on the m2nano, you might want a schmitt trigger as a gate drive for the mosfet for clean engraving. But attiny84 has two PWM ports that aren’t hardware serial ports, and really has 8 GPIO ports free that aren’t RESET or serial.

But an ESP32 is much more capable and only a few dollars. :slight_smile:

Not really MeerK40t for sure, but you could absolutely make a M2 Nano knockoff board that does the same work as the M2 Nano, for a nice little Arduino. I have such a project but it’s little more than planning stage and not too far into that.

I also, have a Arduino Uno and a couple stepper boards my brother bought a while back, so I’m not really lacking the hardware there. But, it doesn’t seem like a major project but I’ve never done them before.

The EgvParser code is actually a lot smaller than the devices code as a whole. I don’t actually think the code would be that massive especially with my better understanding. I’d actually code up the egv parser a lot differently now, since I better understand the states its setting. The speedcodes don’t really need to be right, at least not really. They would actually scale with regard to the CPU used and are basically always just fed into a counter thing. The type of board is set in all the software because it shifts. You’re converting a 16-bit number into an amount of time to wait. And the formulas for that are pretty much linear. You might require small bit of multiplication there. But, even the M2 Nano’s speed codes are all off by 8.9% (comparing the chinese software code with the actual values).

The homing operation is it’s own function too. Go this direction until you detect the end stop, and this direction until you hit something else. There’s also some cursory acceleration and deceleration code that might need to be somewhat duplicated.

For most of the rest I’m not a hardware guru so I’d think @mcdanlj likely has some very solid points.

I don’t think, any part is too hard but I tend to have other stuff to do. It’s part of the reason for the video. Generally explaining what it does makes it easier to explain how easy it would be to do the same thing quite easily, even if I don’t really know the specifics.

Also, the parsing gets easier when you consider things like the ascii code for A is 0x41 and it’s just cutting off that 0x4 bit. Which is one of the charms of ascii. The parsing will undoubtedly have shortcuts like that.

1 Like

Like @Tatarize I have other kettles on the boil, but information for anyone else interested in this project…

attiny84: 20Mhz clock, 8K flash instruction memory, 512 bytes sram data, 5V, pretty robust I/O, only slightly more expensive than dirt ($1-$2 in onesies)

ESP32: 72MHz clock, dual core, wifi and bluetooth, 3.3V, GPIOs reported sometimes 5V tolerant but don’t count on it, 0.5MB SRAM, several MB (several variants in different sizes) flash memory for program, roughly the same price as the attiny84. ($1 for the chip, $2-$4 for the board with flash and wifi antenna, $8-20 for complete dev boards depending on desired functionality; $20 gets you a built-in display and battery controller.) WiFi is better isolated than the best USB cables you can buy! And the API is well documented, supported, and robust; it’s done by sprite_tm (famous for, among other things, installing Linux on his hard drive. Not installing Linux on his computer’s hard drive. I mean, running Linux on the controller on a hard drive… Then for using the ESP32 to make a mini mac. But I digress.)

The atttiny is available in a through-hole part and is easy to solder, whereas the ESP32 boards are 2mm castellated boards and thus slightly more fiddly to solder.

Sadly 99 out of 100 tutorials for getting started with the attiny84 show how to use arduino for it, but I think this is one of those things that would be clearer and simpler with pure C and leaving out the weight of the whole C++ framework. Here’s a blog post with starting example:

I’d still go with ESP32, myself. The ESP32-WROOM-32 is less than $3 from mouser, and still only $4 from digikey. $10 gives you a breakout board with USB on it for programming. Cheaper than arduino.

I think that except for the schmitt trigger, this board from Bart Dring already has everything you want — takes a $10 board, and uses trinamic drivers which are frankly awesome. I’d see whether the schmitt trigger is necessary before adding it.

So if anyone finds this idea interesting, there’s an ideal platform for it! You could reduce the cost substantially by integrating the ESP32-WROOM-32 and stepper driver chips directly instead of building on dev board and step sticks, but it’s already pretty cheap.

1 Like

Well, part of the desire would be to be able to make such things scalable. I’d think you’d want:

  • Ability to duplicate the M2 Nano’s functionality.
  • Then the ability to add functionality to that scheme, zbed, extruder, pwm control.
  • Eventually the ability to have a thousand of them stamped out and sold on the cheap. Duplicating the wire hookups for the M2 Nano.

I’m also not sure you’d need something the speed of arduino in pure C, pretty sure you can leave most of the power on the table since it doesn’t really require math. It’s a great project, but, I dunno enough hardware. And I’d probably just code it on an Arduino since I have one and it’s basic for hardware noobs like myself. I mean with a little more functionality you’re looking at a board that needs like 10 dollars of chips to compete with a boards that run 250 bucks. Mostly since it doesn’t need gcode or to parse anything harder than an ascii stream, the hardware requirements are really low. Though hands on testing might find some things I’ve missed.

1 Like

Well, you can program the ESP32 with Arduino if you want to, and the C++ doesn’t really make it slower. It’s just if almost everything you are doing is setting up timers, I thought it would be easier not to jump through the Arduino hoops. But it’s all available. :slight_smile:

Bart has other boards with more channels. And with the available space on the ESP32, you could actually have a board that interprets gcode and lhymicro-gl. And has a web front end. For cheap. TMC2209 stepper drivers — a huge cut above the old A4988, and allowing sensorless homing, are $2.74 in onesies from Mouser; $1.59 in thousands

Again, the ESP32 itself is cheaper than the Arduino boards, and you can use the Arduino environment to program for it. I just did exactly that for my wife’s Time Turner.


I think I was tired last night because I got focused on whether the attiny84 would be enough to build a replacement board. If you are using a full-blown arduino, or equivalent large avr cpu, or an ESP32, it makes so much more sense to just add a grbl feature that implements lhymicro-gl as a control language; then you’d have both lhymicro-gl and gcode in one board with one firmware. G6 still encodes text lines for the commands; I think that “switch to interpreting lhymicro-gl” would be an M code.

I wonder whether an argument to M452 Select Laser Printer Mode to select lhymicro-gl would be the “obvious” way to implement this?

Joe, who does some of the hardware stuff, is looking into my idle speculation that if you could get the Arduino to be like the CH341 (apparently there’s a compatibility mode thing with a CH340). You could make the board transparent. Since all Whisperer and LaserDrw see is the CH341 chip, if your first point of contact with the board is a CH341 and you can take 32 byte packets that are \x00 (30 ascii bytes) 1crc-byte, you might just be able to hot swap that board without any software noticing it’s not a real M2.

Since lhymicro-gl is such a low level language it’s harder to write. I have implementations of bresenham-zingl bezier curves so that I can draw pixel perfect curves. Because really, with pretty much raw access, and the ability to break a curve into diagonal and orthogonal moves, you can do that sort of thing. People would have to cook up their own bresenham line draw algorithms.

I have seen these sorts of things offered up before. I think Marlin or something had a special raster language or something in some branch. And while that could clearly work I thought much of the charm of the scheme was getting away from gcode interpretation. But, I could see points where it might be nice to have much more raw access in a sort of gcode pocket dimension. Though, I could make MeerK40t just pump out gcode, and short of some rasters it would tend to work quite well.


My first thought was how to just be able to talk the same protocol. It was then realizing that building it on top of grbl or one of its descendents might make it even easier made me wonder whether it could be bilingual…

For Marlin, do you something different than G6 that just merged? It had been sitting around for a long time.


The gcode just points it at raw data pages.

My idea with the M code I was thinking about would be just to switch it from taking gcode to talking lhymicro-gl, as you suggest doing by recognizing the initial data packet, which seems clever.

I thought a single board that could work with meerk40t, whisperer, laserweb, lightburn, etc would be interesting. And, quite possibly, quite cheap.