Skip to content
Demitrios V edited this page Apr 23, 2020 · 14 revisions
For the intrepid maker, hacker, programmer,... here is some information on how this firmware is being developed.

The Local Build System   Automated Builds, Travis-CI  

A "Porting" Plan

Objectives

  • minimal changes to the original Marlin source code
  • preserve Marlin functionality and behaviors
  • explicitly document and control the build process
  • create an "optimal" port for Monoprice MP Mini Delta
  • command-line build, automated build process

Strategy

  • use make and a single Makefile to explicitly document and control the build process
  • no changes to the original Marlin source, create a separate directory to hold modified Marlin source files
  • no changes to the CPU SDK (STM32Cube), create a separate directory to hold SDK changes and customizations
  • to limit changes to Marlin source files, use an "always_include.h" header file to help "re-map" Marlin's "AVR-ness" to the "STM32F0" processor family
  • to limit changes to Marlin source files, use empty header files to satisfy included Arduino library header files
  • place and run the tool-chain via changeroot or docker virtual machine (VM)
  • use GitHub / Travis-CI for source control, automated builds and deployment

Execution Notes

Overall, things went more or less according to plan. I was hoping to change fewer Marlin source files, but some of the Marlin source files needed small (benign) changes to effect the port, and I found a few bugs in Marlin which I hadn't anticipated (which led to even more changes). I grossly underestimated the number of alterations to Marlin_main.cpp -- thinking initially that I'd need only to change a few setup and initialization things. The file does preserve the original Marlin code, but in hindsight, Marlin_main.cpp probably should have become Marlin_main_stm32.cpp and treated like a port-specific rewrite of the original file (similar to MarlinSerial_stm32.cpp, etc.).

Source Notes

(excerpt from HAL_stm32.h)

/* NOTE: include this file before all others (e.g. gcc -include HAL_stm32.h)
 * to select the cpu device (CMSIS, STM32F070xB) and to configure the HAL
 * driver appropriately. ALSO, this file provides several work-arounds to
 * "preempt" the inclusion of a few of the original Marlin include files
 * that would otherwise cause problems when compiling for the STM32F070xB.
 * An included file that is NOT part of Marlin (e.g.'include <avr/eeprom.h>')
 * is created as an empty file and placed in the "included files search path"
 * to satisfy the reference to the file. Using these techniques, then, our
 * port requires only minimal changes to the original Marlin source files. 
 *
 * Highlights of the required changes (*file compatible with the original):
 * boards.h                      - added MALYAN_M300 board definition*
 * pins.h                        - include MALYAN_M300 pins description*
 * pins_MALYAN_M300.h            - created, the MALYAN_M300 pins description
 * Configuration.h               - Marlin configuration for MALYAN_M300
 * Configuration_adv.h           - Marlin configuration for MALYAN_M300
 * delay.h                       - minor (benign) change for MALYAN_M300*
 * cardreader.h                  - minor (benign) change for MALYAN_M300*
 * stepper.h                     - minor (benign) change for MALYAN_M300*
 * stepper.cpp                   - minor (benign) change for MALYAN_M300*
 * temperature.h                 - minor (benign) change for MALYAN_M300*
 * temperature.cpp               - minor (benign) change for MALYAN_M300*
 * Marlin_main.cpp               - add inverted KILL pin for MALYAN_M300*
 * HAL_stm32.h                   - replacement for HAL.h
 * HAL_stm32.c                   - HAL "glue" to support the STM32F070xB
 * MarlinSerial_stm32.cpp        - replacement for MarlinSerial.cpp
 * Sd2Card_stm32.cpp             - replacement for Sd2Card.cpp
 * configuration_store_stm32.cpp - replacement for configuration_store.cpp
 * watchdog_stm32.cpp            - replacement for watchdog.cpp
 * malyanlcd_stm32.cpp           - replacement for malyanlcd.cpp
 */

Configuration Options

(excerpt from HAL_stm32.h)

// The 60-watt power supply of the Monoprice Mini Delta doesn't provide
// sufficient power to heat the nozzle and the build plate at the same
// time. We slightly modify the temperature isr (see temperature.cpp)
// to ensure that only one heater is active at a time. Our VERY simple
// implementation, though, limits "full-on" for the heat bed to 99.2%,
// and always gives priority to hotend -- hopefully not a problem.
#define ONLY_ONE_HEATER_AT_A_TIME  1

#if MAKE_05ALIMIT
#undef  ONLY_ONE_HEATER_AT_A_TIME
#define ONLY_ONE_HEATER_AT_A_TIME  1
#endif

#if MAKE_10ALIMIT
#undef  ONLY_ONE_HEATER_AT_A_TIME
#define ONLY_ONE_HEATER_AT_A_TIME  0
#endif

// Configure IO as Marlin directs (as opposed to configuring all of the
// IO at the program's start) -- nice idea, but requires a workaround to
// use hardware pwm (FAN_USES_HARDWARE_PWM). (see the GPIO_20 hack below)
#define CONFIGURE_IO_INDIVIDUALLY  0

// Configure the fan output to use hardware pwm
#define FAN_USES_HARDWARE_PWM  1

// The single fan of the Monoprice Mini Delta is normally configured as
// an auto-cooling extruder fan. Set CONFIGURE_FAN_AS_PART_COOLING to 1
// to use M106/M107 to control the fan (NOT RECOMMENDED).
#define CONFIGURE_FAN_AS_PART_COOLING  0

// The stock firmware of the Monoprice Mini Delta places the "front" of
// the build plate away from the LCD display. Set ROTATE_TOWER_AXES to 1
// to redefine the stepper motor axes and thus rotate the tower axes.
// Specifically, X<=Y, Y<=Z, and Z<=X (where A<=B means A becomes B)
#define ROTATE_TOWER_AXES  1

// Invert the direction of a stepper motor by setting the corresponding
// bit(X,Y,Z,E) in STEPPER_DIRECTION_XYZE. It seems that Monoprice does
// not configure the stepper motors consistently, so it may be necessary
// adjust this value. Use the M503 report from the stock firmware to
// determine an appropriate value.
// e.g. if the stock firmware M503 reports:
// (M562 XYZE) XYZABCD---+... use 0b0001 (0x1) 
// (M562 XYZE) XYZABCD+++-... use 0b1110 (0xe)
// (M562 XYZE) XYZABCD----... use 0b0000 (0x0)
// (M562 XYZE) XYZABCD++++... use 0b1111 (0xf)
//
// NOTE! IMPORTANT! Be careful here, if we rotate the tower axes
// (#define ROTATE_TOWER_AXES  1), then the output from the stock
// M503 (M562) command must be adjusted (mapped) accordingly.
// e.g. if the stock firmware M503 reports:
// (M562 XYZE) XYZABCD+---... use 0b0100 (0x4) 
// (M562 XYZE) XYZABCD-+--... use 0b0010 (0x2)
// (M562 XYZE) XYZABCD--+-... use 0b1000 (0x8)
// 
#ifndef INVERT_STEPPER_DIRECTION_XYZE
#define INVERT_STEPPER_DIRECTION_XYZE  0b0001
#endif

// Custom codes, M988 and M989, open and close an output log file
// in the current working directory. Use a DOS 8.3 name for the
// file. "#define OVERLY_SIMPLISTIC_OUTPUT_LOGGING_HACK  1" to
// enable this feature.
// e.g.
// M988 logfile.txt  ; start writing output to "logfile.txt"
// M503              ; report settings
// M989              ; stop writing (close) the log file
//
#define OVERLY_SIMPLISTIC_OUTPUT_LOGGING_HACK  1

The Local Build System

The build system is linux based, specifically Debian "buster" with the following additional packages installed:

(ARM bare metal compiler, libraries, and tools)

$ apt-get install build-essential gcc-arm-none-eabi binutils-arm-none-eabi 
$ apt-get install libnewlib-arm-none-eabi libnewlib-dev libstdc++\-arm-none-eabi-newlib 
$ apt-get install gdb-multiarch openocd telnet emacs-nox

(basic git -- for GitHub, ssh, ...)

$ apt-get install git quilt patchutils openssh-client ca-certificates gnupg wget curl

(optional, but I find useful)

$ apt-get install sudo rename xsltproc picocom zip unzip p7zip-full p7zip-rar

Compiling

The "Makefile" documents the entire build process. The default target (make) and the "all" target (make all) are good places to start. The "Makefile" also defines the release number (e.g. RELEASE = 00).

Generate two (2) "firmware.bin" files -- one for use with a 60watt power adapter (05Alimit) and one for use with a 120watt power adapter (10Alimit).

$ make all

Generate a single "firmware.bin" file with the prevailing configuration of the original Marlin4MPDM source (currently matches the 10Alimit configuration).

$ make

Automated Build System, Travis-CI

The automated build site, Travis-CI, compiles the firmware automatically whenever a change is pushed to the mpmd_marlin_1.1.x repository. A tagged commit, when the tag matches the pattern of a version number, triggers the (Travis-CI) process to build and deploy a release.

I like the way the automated build process has come together. We select Ubuntu linux for Travis-CI's basic build processes, but the arm cross compilation tools (arm gcc tool chain) reside in a minimal (Debian) docker container. Travis-CI launches the docker container attached to the source directory and runs a single "make" command to build the firmware. After which, IF the build is tagged with a version number, Travis-CI executes its deploy stage. Travis-CI runs "make" one more time (in Ubuntu) to generate the zip file of the SD card contents before returning the build artifacts (.bin files, zipped SD card contents, etc.) to GitHub. The whole thing is neatly described in two short files: .travis_dockerfile to create the docker container and .travis.yml to direct the Travis-CI automation. The Travis-CI automation particulars are completely separate from the details of building the firmware (captured in the Makefile). Very nice indeed.