Wednesday, January 20, 2010

Project: FiveD on Arduino

I've been looking at the firmware lately, specifically the FiveD firmware for Sanguino and the claims that the Arduino is simply too small.

I disagree.

Official FiveD has a liberal sprinkling of floating point math, some even in interrupt context! The floating point library for Atmega takes up over 2k. The FiveD firmware is written in C++, which is lovely on desktop systems but adds lots of costly and unnecessary overhead in the context of microcontrollers.

So, I'm rewriting the firmware in C with 100% integer math. My target is to keep it under 14k so I can keep the bootloader, but I'll settle for 16k if necessary. So far, I've replicated about 95% of the functionality and have used less than 9k of the 16k available on my Arduino.

Currently it compiles but is mostly untested. At this stage, expect serious bugs and frequent radical changes. I will make a release when I have successfully printed my first mendel part with it.

If you want to see where I'm up to, FiveD on Arduino at github.

Comments? Suggestions? Bug Fixes? FiveD on Arduino Forum Thread


  1. That sounds very sensible indeed, scaled integer arithmetic is usually somewhat faster as well.

    Floating point math in interrupt functions is scary indeed.

  2. why not just use a new Atmel328 based arduino with twice the space? ( 32K ) the chip costs under $5US and is essentially the same price as the old one, and is 100% pin compatible drop-in replacement.?

    I think the other big issue which still affects the 168/328 chips is the number of pins being used is close to the limit. Eend-stops, heated-beds, valved tips, dual-extruders, etc all take one or more extra pins, and you run can out very quickly on a single machine. Although I've discovered that the unused "analog" pins are 100% capable of being used as a digital pin too. :-)

  3. Buzz, official FiveD apparently doesn't fit on 328 either

    I'm using analog pins as digital I/O, still don't have enough space for max end stops. if I need more I/O I'll stick some of the outputs on a shift reg and use the SPI bus. see pinout.h for my current pin assignments (and some macros which should probably be somewher else). I think I have just one pin left and I'll probably use that for stepper enable/disable

  4. Triffid: Premature optimisation is root of all evil...

    I think you need a beefier chip to implement a working version of the firmware, and optimise later.

    Im thinking along the line of buying Seeduino (arduino mega clone) for 50$:

  5. I think you should only refrain from optimizations if it makes this more complex. Even some additional complexity is acceptable when the memory constraints would apply to many people. If there's no additional complexity this is valuable to the wider community.

    It's not just about memory size, more importantly: integer math is faster! I know from experience that with 4x stepper drivers with 1/16th step, you need a lot of interrupts to drive the motors at a higher speed. The current firmware will often drop/ignore some of the serial input because it doesn't handle it it time. This means that you can't run 4 steppers because of inefficiency.

    So, I think this is a valuable effort! Please use the same valuable compatible with the pins.h and properties.h files, this will allow other to test and compare more easily.

    B.t.w. allowing you to use discrete steps as G-Code input would even be better (pre-processing on the host). That way you'll be sure there are only integers.

  6. Way to go. I started rewriting the 5D code in C but got hung up on trying to do the fifth axis without the need for another stepper control line from the motherboard. (Do some sort of sync over the RS-422 line) I look forward to seeing your progress.

  7. Hi Triffid,

    i got a small patch for you that makes it less picky on CR/LF issue :)


    diff --git a/mendel/gcode.c b/mendel/gcode.c
    index 12479fa..335ac4d 100644
    --- a/mendel/gcode.c
    +++ b/mendel/gcode.c
    @@ -105,7 +105,7 @@ void scan_char(uint8_t c) {
    // process previous field
    if (last_field) {
    // check if we're seeing a new field or end of line
    - if ((indexof(c, alphabet) >= 0) || (c == 10)) {
    + if ((indexof(c, alphabet) >= 0) || (c == 10) || (c == 13)) {
    switch (last_field) {
    case 'G':
    next_target.G = read_digit.mantissa;
    @@ -263,7 +263,7 @@ void scan_char(uint8_t c) {

    // end of line
    - if (c == 10) {
    + if ((c == 10) || (c == 13)) {
    // process
    diff --git a/mendel/serial.c b/mendel/serial.c
    index c431bce..7279047 100644
    --- a/mendel/serial.c
    +++ b/mendel/serial.c
    @@ -78,6 +78,9 @@ uint16_t serial_recvblock(uint8_t *block, int blocksize)

    void serial_writechar(uint8_t data)
    + if (data == 10)
    + serial_writechar(13);
    // check if interrupts are enabled
    if (SREG & MASK(SREG_I)) {
    // if they are, we should be ok to block

  8. reinoud, it basically ignores CR at the moment- anything that's not a recognised field name, start of comment or numeric is ignored. I don't think any of our tools produce gcode with CR but not LF. If it becomes an issue, I'll add your patch :)

  9. Thanks, I'll undoubtedly use fived on Arduino if you make it possible.