Close

Bootloader, or, From Hell's Heart, I stab at thee..

A project log for Monoprice Mini Marlin 2.0 Support

Getting Marlin to run on the Monoprice Mini/Malyan M200.

jc-nelsonJ.C. Nelson 05/11/2018 at 22:420 Comments

As I noted in my last installment, all was well so long as I did not turn my printer off. And the truth was, I didn't turn it off often...but what was happening was that if I re-flashed the printer, it started fine. If I turned it on from a cold boot, it would start one in twenty times.

The other times, it emitted a high pitched whining like a bat in a blender, which sounded like it was coming from the Z axis motor.

To figure this out, I started by making a build of Marlin which would dump the bootloader. You may recall that Malyan set the protect bit on, but that bit only applies to debug tools. The firmware itself has no issues in reading that area, so I dumped it to SD and began to do two things in parallel:

First, in binaryNinja, I disassembled the bootloader.

Secondly, I began testing. 

If I'd been comfortable destroying my only functioning main board, I could have soldered some wires to it and debugged it directly once I disabled protecting and reflashed the bootloader. 

I was not comfortable with doing this because my version of fine soldering looks like Mt. St. Solder errupted and all the little components are running terrified as molten metal rains down on them.

But I am a coder, and it occured to me that I could figure it out without a debugger. The mainboard doesn't come with a fan or even a damned activity LED...but it does have a fan port...

So first I wrote a function, turnFanOn(), which simply set the pinmode of PB8 to output, set it high, and went into an eternal loop. Sure, the watchdog would punk me at some point, but not before I knew if it worked.

Putting int loop():

No dice.

Putting it in setup()

Nope.

Looking at SMT32Duino, I found the main() funciton. and dropped it in there.

Nada.

And now I had a problem. The earlier calls are so early the system isn't initialized. digitalWrite ain't going to happen, and the same with pinMode(). But the bootloader had been running, and obviously accessing pins on the same devices.

So instead of using functions, did some quick tracing on a bluepill and produced the following code, which writes to the registers directly:

void turnOnFan()
{
  long *cr = ((long *)(0x40010c04)); //&GPIOB_BASE->CRH;
  long tmp = *cr;

  tmp &= ~(0xF << ((8 & 0x7) * 4));
  tmp |= 0x3 << ((8 & 0x7) * 4);

  *cr = tmp;

  // turn on PB3 & PB8
  *((long *)(0x40010c10)) = (1 << 8) | (1 << 3);

  for (;;) {}
}

Now, that's an UGLY way to do it, but it works. Moving it back into the pre-init, the sys init, and so on, however, did not work. All that was left was the startup assembly. So, screw it, I said. At the top of the reset handler, I put in a call--and every time, the fan turned on like magic. Now it was simply a matter of figuring out where things went wrong, and it turns out they went wrong in a function not too far off. The bootloader is watching some memory addresses that trigger operations which fault. If the maple core gets to initialize itself, they're all erased, but I never did figure out what it was. The solution was to turn off interrupts while initializing, then re-enable them.

void __attribute__((noreturn)) start_c(void) {
    // On M200 derived boards, there's interrupt functions running from the
    // bootloader. Once init is done, these are gone, so disable interrupts
    // until then.
    asm volatile("cpsid i");
    struct rom_img_cfg *img_cfg = (struct rom_img_cfg*)&_lm_rom_img_cfgp;
    int *src = img_cfg->img_start;
    int *dst = (int*)&__data_start__;
    int exit_code;

    /* Initialize .data, if necessary. */
    if (src != dst) {
        int *end = (int*)&__data_end__;
        while (dst < end) {
            *dst++ = *src++;
        }
    }

And the ringing? It turns out that in maple, the default error handler pulses the error LED, PC13. And in my pins definition? PC13 is the extruder direction pin. So the error pulse was causing the extruder to switch directions over and over, whining.

At last, I could boot cleanly.

If only the LCD worked...

Discussions