Help needed with code optimisation please

Hi guys,

So here's my situation, I've created a prototype 3 axis CNC from broken printers and scanners. I have 2 unipolar steppers from an old dot matrix and a bipolar from a scanner. I'm using an ATmega8 (with the arduino bootloarder to make things easier for me) to interface a parallel port to the steppers. On the PC side I'm using EMC2 to run the show.
I have a step and direction input into the ATmega for each axis and have 4 outputs for each stepper. For now I've just patched into the dot matrix PCB to use the original transistor circuitry and am using an L293D for the bipolar (I only have messy hand drawn schematics so I can't post them up but hopefully you'll get the idea). The machine itself and the electronics are working OK.

The problem I have is that the machine looses step (fairly badly) when 2 or 3 the axis are moving at the same time. If I run the machine VERY slowly then it's OK but I'm sure that the code can probably be optimised a bit better but I'm not sure how.

I've attached my code to this post, any suggestions or improvements would be much appreciated,

Thanks

arduino_cnc_z_fullstep.pde (4.1 KB)

Although your code could be streamlined a little, I don't see anything that will take up much time - as long as you don't work in debug mode where all that serial output of debug values might bog you down. What kind of data rate are you expecting on the Port C as input?

Korman

Thanks for your reply Korman.
The inputs are simply coming directly from the parallel port outputs (from EMC2) and are just a logic high to indicate a step on one of the step input pins and either a high or low to determine the direction on the corresponding direction input pin (total of 6 input pins, 3 step and 3 direction).

I will try to dig through my sketchbooks to find one of my roughly drawn schematics and post it up.

Thanks

I don't have a working board to profile against at the moment so I'm going to throw out this untested and un-profiled code for you to try.

I reduced the code for me to better visualize what's going.

Switched things that should be contants to constants through the use of anonymous 'enums' instead.

Got rid of memory wasting 'const type' declarations that reserved runtime memory space unnecessarily also reducing unnecessary memory fetches.

A next step would be to simplify the code as Korman aluded to.

Of course the out of step problem you mention may be due to the respose time of the various steppers and motors.

//#define DEBUG

// THE USE OF CONSTANTS CAN ALLOW THE COMPILER TO MAKE OPTIMIZATIONS THAT THE USE OF VARIABLES PRECLUDE

// ENUM ARE EFFECTIVLEY CONSTANTS AND OCCUPY NO MEMORY (OUTSIDE OF COMPILE TIME, UNLIKE 'const type' DECLARATIONS)
enum
{
      inputStepMask     = B00101010

    , inputXStepMask    = B00100000
    , inputYStepMask    = B00001000
    , inputZStepMask    = B00000010

    , inputXDirMask     = B00010000
    , inputYDirMask     = B00000100
    , inputZDirMask     = B00000001

    , outputXMask       = B00111100     // PORTD 4bits for X
    , outputYMaskD      = B11000000     // PORTD 2bits for Y
    , outputYMaskB      = B00000011     // PORTB 2bits for Y
    , outputZMask       = B00111100     // PORTB 4bits for Z
};


// --- CLOBAL CONSTANTS
const uint8_t fullstepSequence[4] =
{
      B00001000
    , B00000010
    , B00000100
    , B00000001
};
          
const uint8_t halfstepSequence[8] =
{
      B00001001
    , B00000001
    , B00000101
    , B00000100
    , B00000110
    , B00000010
    , B00001010
    , B00001000
};
             

// --- CLOBAL VARIABLES       

int     xCurrentStep        = 0;
int     yCurrentStep        = 0;
int     zCurrentStep        = 0;

uint8_t inputStepLastState  = B00000000;
uint8_t inputCurrentState   = B00000000;


// --- DEBUG ROUTINES

#ifndef DEBUG
    #define DEBUG_STRING(STRING)
#else
    #define DEBUG_STRING(STRING)    DebugStr(STRING)

    void DebugStr(const char str[] strMessage)
    {
        Serial.print(strMessage);
    }
#endif


// --- SUBROUTINES

void outputSteps()
{
    if ( (inputCurrentState & inputXStepMask) == inputXStepMask )
    {
        DEBUG_STRING("x ");
        if ( (inputCurrentState & inputXDirMask) == inputXDirMask )
        {
            DEBUG_STRING("< ");
            (void)((xCurrentStep == 0) ? xCurrentStep = 7 : xCurrentStep--);
        }
        else
        {
            DEBUG_STRING("> ");
            (void)((xCurrentStep == 7) ? xCurrentStep = 0 : xCurrentStep++);
        }

        DEBUG_STRING(xCurrentStep);
        DEBUG_STRING(" ");
        Serial.println(micros());
    }

    if ( (inputCurrentState & inputYStepMask) == inputYStepMask )
    {
        DEBUG_STRING("y ");
        if ( (inputCurrentState & inputYDirMask) == inputYDirMask )
        {
            DEBUG_STRING("< ");
            (void)((yCurrentStep == 0) ? yCurrentStep = 7 : yCurrentStep--);
        }
        else
        {
            DEBUG_STRING("> ");
            (void)((yCurrentStep == 7) ? yCurrentStep = 0 : yCurrentStep++);
        }
        DEBUG_STRING(yCurrentStep);
        DEBUG_STRING(" ");

        Serial.println(micros());
    }

    if ( (inputCurrentState & inputZStepMask) == inputZStepMask )
    {
        DEBUG_STRING("z ");  
        if ( (inputCurrentState & inputZDirMask) == inputZDirMask )
        {
            DEBUG_STRING("< ");
            (void)((zCurrentStep == 0) ? zCurrentStep = 3 : zCurrentStep--);
        }
        else
        {
            DEBUG_STRING("> ");
            (void)((zCurrentStep == 3) ? zCurrentStep = 0 : zCurrentStep++);
        }

        DEBUG_STRING(zCurrentStep);
        DEBUG_STRING(" ");
        Serial.println(micros());
    }

    PORTD = (halfstepSequence[xCurrentStep] << 2) | ((halfstepSequence[yCurrentStep] << 4) & outputYMaskD); // x (B00111100) & yD (B11000000)
    PORTB = (fullstepSequence[zCurrentStep] << 2) | ((halfstepSequence[yCurrentStep]) & outputYMaskB);      // z (B00111100) & yB (B00000011)
}


// --- REQUIRED ROUTINES

void loop()
{
    if ( (PINC & inputStepMask) != inputStepLastState )
    {
        inputCurrentState   = PINC;
        inputStepLastState  = inputCurrentState & inputStepMask;
        if ( (inputCurrentState & inputStepMask) != 0 )
        {
            outputSteps();
        }
    }
}


void setup()
{
    DDRC = /*DDRC |*/ B00000000;    // Set PORTC as input
    DDRB = /*DDRB |*/ B00111111;    // Set PORTB as outputs
    DDRD = DDRD | B11111100;        // Set PORTD as outputs
    
    Serial.begin(115200);                            
    Serial.println("---BEGIN---");
}

Thanks for the replies guys, and many thanks to lloyddean... this is the first time I've asked for help with some code and I was definitely not expecting anyone to rewrite it for me!
I've uploaded new new sketch and have been testing the machine for a few hours now (at roughly twice the speed that I previously was), and I'm very pleased to say that it seems to have corrected my lost step issue, I don't fully understand all of the changes that lloyddean has made but I intend to do my research to find out.

Thanks again guys :slight_smile: