Welcome! Log In Create A New Profile

Advanced

Super Super Firmware Optimization (giving you more free memory!)

Posted by ErikDeBruijn 
Super Super Firmware Optimization (giving you more free memory!)
October 28, 2008 05:19PM
I've changed something very simple in the Arduino firmware (I use the GCode version, but it's probably applicable to any version). Right now, an if condition is checked at runtime to see whether measurement of the thermistor or thermocouple should be done. For those of use with the thermocouple, the code about thermistors is useless (including the lookup table of almost 200 bytes), and for those with the thermistor, the thermocouple code is unneeded (just a couple of bytes).

There is no reason to compile in both and burn them into the device.

In _init.pde, instead of using -1 and 0 (or any other analog pin-nr.):
// Keep the applicable line uncommented, comment the other:
#define EXTRUDER_THERMISTOR_PIN    0  //comment out to use THERMOCOUPLE instead. Uncomment next line.
//#define EXTRUDER_THERMOCOUPLE_PIN  0    //comment out to use THERMISTOR.

When either one is commented out, you can use #ifdef and #ifndef (if defined and if not defined). These conditions are not checked by the Atmega chip, but by the compiler to decide what to put there.

Now the thermistor table can be surrounded by:
#ifdef EXTRUDER_THERMISTOR_PIN
#define NUMTEMPS 20
short temptable[NUMTEMPS][2] = {
   {1, 841},
...
etc...
...
   {1008, 3}
};
#endif

The extruder_get_temperature() should contain these two statements:
int extruder_get_temperature()
{
#ifdef EXTRUDER_THERMISTOR_PIN
return extruder_read_thermistor();
#endif
#ifndef EXTRUDER_THERMISTOR_PIN
return extruder_read_thermocouple();
#endif
}

#ifdef EXTRUDER_THERMISTOR_PIN
int extruder_read_thermistor()
{ ... }
#endif

#ifndef EXTRUDER_THERMISTOR_PIN
int extruder_read_thermocouple()
{ ... }
#endif

If there aren't (which seems to be the case), there should be an optimization of runtime 'if conditions' that check against constants only.

Also, if a function doesn't exist (isn't called) it will still take up memory. Taking this a step further and removing extruder_get_temperature() all together frees up more memory. You need to replace each invocation (all three of them?) of the function by something similar to this:
#ifdef EXTRUDER_THERMISTOR_PIN
  int current_celsius = extruder_read_thermistor();
#endif
#ifndef EXTRUDER_THERMISTOR_PIN
  int current_celsius = extruder_read_thermocouple();
#endif

I'm not sure why, but the compiler should be responsible for doing this, because readability now goes down a bit. Readability doesn't need to make code sub-optimal in terms of code usage.

Those with a thermistor save 106 bytes. For those with a thermocouple it's considerably more: 240 bytes saved. Both may not seem like much, but it would be cool to include some 'special moves' before a print (M code 42 is unimplemented!). This would be nice for those of use with a thermocouple. tongue sticking out smiley
We could also increase verbosity of the output, but that's boring (but more useful).
Besides, with more people having a Sanguino, those with Arduinos may be forced to upgrade when firmware becomes more complex. Arguably, it's human nature to use up all resources that are available. smiling smiley Wasting less bytes in the firmware would allow them to keep using the Arduino longer. It would also be another good reason to favor a thermocouple (besides extra reliability and simplicity). Thermistors are really cheap though. It's uncontested that that's a good selling point!

I think a similar memory gain can be achieved by allowing only metric or imperial on a RepRap. The host software can convert it and process GCode in the metric that was used.


Regards,

Erik de Bruijn
[Ultimaker.com] - [blog.erikdebruijn.nl]
Re: Super Super Firmware Optimization (giving you more free memory!)
October 28, 2008 07:14PM
My opinion is that we should either use a much more powerful micro or do the g-code interpreter on the PC and send low level commands to the micro.

On my system the temperature control in the micro is simply read ADC, compare result with the set point sent from the host. A few lines of code which will work with either a thermistor or a thermocouple, with perhaps just an inversion.


[www.hydraraptor.blogspot.com]
Re: Super Super Firmware Optimization (giving you more free memory!)
October 28, 2008 07:36PM
Finding out there was newer firmware (current svn trunk), newer is not always better in every respect:
Binary sketch size: 14914 bytes (of a 14336 byte maximum)

Doh!

What I did to make everything fit...

I've made Gcodes G81-83 optional with a definition, since this takes 794 bytes and seems to be for subtractive CNC, not for additive extrusion. Is this correct?

Now it would fit on a standard 14k Arduino.

My earlier trick got me another 248 bytes (see new extruder.pde below). This is without losing ANY functionality. The code is also a lot shorter, due to less calling of routines that would be virtually empty. My current solution is also more elegant than what I discussed before. Now the only change is in extruder.pde. In _init.pde you need to uncomment what you don't use, like before.

The new extruder.pde:
// Yep, this is actually -*- c++ -*-

#ifdef EXTRUDER_THERMISTOR_PIN
#include "ThermistorTable.h"
#endif

#define EXTRUDER_FORWARD true
#define EXTRUDER_REVERSE false

//these our the default values for the extruder.
int extruder_speed = 128;
int extruder_target_celsius = 0;
int extruder_max_celsius = 0;
byte extruder_heater_low = 64;
byte extruder_heater_high = 255;
byte extruder_heater_current = 0;

//this is for doing encoder based extruder control
int extruder_rpm = 0;
long extruder_delay = 0;
int extruder_error = 0;
int last_extruder_error = 0;
int extruder_error_delta = 0;
bool extruder_direction = EXTRUDER_FORWARD;

void init_extruder()
{
	//default to room temp.
	//extruder_set_temperature(21);
	
	//setup our pins
	pinMode(EXTRUDER_MOTOR_DIR_PIN, OUTPUT);
	pinMode(EXTRUDER_MOTOR_SPEED_PIN, OUTPUT);
	pinMode(EXTRUDER_HEATER_PIN, OUTPUT);
	pinMode(EXTRUDER_FAN_PIN, OUTPUT);
	
	//initialize values
	digitalWrite(EXTRUDER_MOTOR_DIR_PIN, EXTRUDER_FORWARD);
	analogWrite(EXTRUDER_FAN_PIN, 0);
	analogWrite(EXTRUDER_HEATER_PIN, 0);
	analogWrite(EXTRUDER_MOTOR_SPEED_PIN, 0);
}

void extruder_set_direction(bool direction)
{
	extruder_direction = direction;
	digitalWrite(EXTRUDER_MOTOR_DIR_PIN, direction);
}

void extruder_set_speed(byte speed)
{
	analogWrite(EXTRUDER_MOTOR_SPEED_PIN, speed);
}

void extruder_set_cooler(byte speed)
{
	analogWrite(EXTRUDER_FAN_PIN, speed);
}

void extruder_set_temperature(int temp)
{
	extruder_target_celsius = temp;
	extruder_max_celsius = (int)((float)temp * 1.1);
}

/**
*  Samples the temperature and converts it to degrees celsius.
*  Returns degrees celsius.
*/
int extruder_get_temperature()
{
#ifdef EXTRUDER_THERMISTOR_PIN
	int raw = extruder_sample_temperature(EXTRUDER_THERMISTOR_PIN);

	int celsius = 0;
	byte i;

	for (i=1; i raw)
		{
			celsius  = temptable[i-1][1] + 
				(raw - temptable[i-1][0]) * 
				(temptable[1] - temptable[i-1][1]) /
				(temptable[0] - temptable[i-1][0]);

			break;
		}
	}

        // Overflow: Set to last value in the table
        if (i == NUMTEMPS) celsius = temptable[i-1][1];
        // Clamp to byte
        if (celsius > 255) celsius = 255; 
        else if (celsius < 0) celsius = 0; 

	return celsius;
#endif
#ifndef EXTRUDER_THERMISTOR_PIN

	return ( 5.0 * extruder_sample_temperature(EXTRUDER_THERMOCOUPLE_PIN) * 100.0) / 1024.0;
#endif
}

/*
* This function gives us an averaged sample of the analog temperature pin.
*/
int extruder_sample_temperature(byte pin)
{
	// can be smaller when not using a single sample
	#if TEMPERATURE_SAMPLES==1
	return analogRead(pin);
	#endif
	
	int raw = 0;
	
	//read in a certain number of samples

	for (byte i=0; iRegards,

Erik de Bruijn
[Ultimaker.com] - [blog.erikdebruijn.nl]
Re: Super Super Firmware Optimization (giving you more free memory!)
October 28, 2008 07:45PM
nophead. You're right. Although in the thermocouple the advantage isn't huge. The thermistor case is different.

That could save at most 80 bytes. This version is 80 bytes smaller:
int extruder_get_temperature()
{
	return 1; // instead of: ( 5.0 * extruder_sample_temperature(EXTRUDER_THERMOCOUPLE_PIN) * 100.0) / 1024.0;
}

I estimate about 220 bytes saved with host-based temperature conversion.

At least my 'free' solution should be added. There's only a benefit. Temperature conversion could be further done on the host. If we change this, we should do it at this early stage. A choice between imperial and metric could also be made, but i'm unaware of politics or ego's that might be involved here winking smiley


Regards,

Erik de Bruijn
[Ultimaker.com] - [blog.erikdebruijn.nl]
Sorry, only registered users may post in this forum.

Click here to login