Reduce code size to Attiny13

Hi All,

I have a quite simple code which is to big for an Attiny13 (max, 1024 bytes).

#include <math.h>
int piezo_pin = 3;         // the number of the input pin
int FET_pin = 10;          // the number of the output pin 0
int LED_pin = 7;           // the number of the control led pin 1
int maxTemp = 28;          // the maximum allowed FEt temperature
int Nfet_TC_pin = A1;              // the number of the N-FET thermistor
int Nfet_thermistor_adc_val;       //  N-FET thermistor read value
double N_output_voltage;           //  N-FET thermistor output voltage
double N_thermistor_resistance;    //  N-FET thermistor resistance
double N_therm_res_ln;             //  N-FET thermistor log resistance
double N_temperature;              //  N-FET temperature

int Pfet_TC_pin = A2;              // the number of the P-FET thermistor
int Pfet_thermistor_adc_val;       //  P-FET thermistor read value
double P_output_voltage;           //  P-FET thermistor output voltage
double P_thermistor_resistance;    //  P-FET thermistor resistance
double P_therm_res_ln;             //  P-FET thermistor log resistance
double P_temperature;              //  P-FET temperature

int buttonPushCounter = 0;    // counter for the number of button presses
int buttonState = 0;          // current state of the button
int lastButtonState = 0;     // previous state of the button

// the follow variables are long's because the time, measured in miliseconds,
unsigned long previousMillis = 0;         // the last time the output pin was toggled
unsigned long currentMillis = 0;          // current time in ms
const long debounce = 50;                 // the debounce time, increase if the output flickers

void setup()
{

  pinMode(piezo_pin, INPUT);
  pinMode(FET_pin, OUTPUT);
  pinMode(LED_pin, OUTPUT);
  pinMode(Nfet_TC_pin, INPUT);
  pinMode(Pfet_TC_pin, INPUT);
}

void loop()
{

// N-FET thermistor temperature calculation

  Nfet_thermistor_adc_val = analogRead(Nfet_TC_pin);
  N_output_voltage = ( (Nfet_thermistor_adc_val * 5.0) / 1023.0 );
  N_thermistor_resistance = ( ( 5 * ( 10.0 / N_output_voltage ) ) - 10 ); /* Resistance in kilo ohms */
  N_thermistor_resistance = N_thermistor_resistance * 1000 ; /* Resistance in ohms   */
  N_therm_res_ln = log(N_thermistor_resistance);
  /*  Steinhart-Hart Thermistor Equation: */
  /*  Temperature in Kelvin = 1 / (A + B[ln(R)] + C[ln(R)]^3)   */
  /*  where A = 0.001129148, B = 0.000234125 and C = 8.76741*10^-8  */
  N_temperature = ( 1 / ( 0.001129148 + ( 0.000234125 * N_therm_res_ln ) + ( 0.0000000876741 * N_therm_res_ln * N_therm_res_ln * N_therm_res_ln ) ) ); /* Temperature in Kelvin */
  N_temperature = N_temperature - 273.15; /* Temperature in degree Celsius */


  //delay(100);

// P-FET thermistor temperature calculation

  Pfet_thermistor_adc_val = analogRead(Pfet_TC_pin);
  P_output_voltage = ( (Pfet_thermistor_adc_val * 5.0) / 1023.0 );
  P_thermistor_resistance = ( ( 5 * ( 10.0 / P_output_voltage ) ) - 10 ); /* Resistance in kilo ohms */
  P_thermistor_resistance = P_thermistor_resistance * 1000 ; /* Resistance in ohms   */
  P_therm_res_ln = log(P_thermistor_resistance);
  /*  Steinhart-Hart Thermistor Equation: */
  /*  Temperature in Kelvin = 1 / (A + B[ln(R)] + C[ln(R)]^3)   */
  /*  where A = 0.001129148, B = 0.000234125 and C = 8.76741*10^-8  */
  P_temperature = ( 1 / ( 0.001129148 + ( 0.000234125 * P_therm_res_ln ) + ( 0.0000000876741 * P_therm_res_ln * P_therm_res_ln * P_therm_res_ln ) ) ); /* Temperature in Kelvin */
  P_temperature = P_temperature - 273.15; /* Temperature in degree Celsius */
  
  
// switch when piezzo button is oushed
currentMillis = millis();
if (currentMillis - previousMillis >= debounce){
  previousMillis = currentMillis;

  // read the pushbutton input pin:
  buttonState = digitalRead(piezo_pin);
  
  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    
  // if the state has changed, increment the counter
    if (buttonState == LOW) {
      
  // if the current state is HIGH then the button went from off to on:
      buttonPushCounter++;
    }
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;
  
}

// turns on the heating at every two button pushes
  
if (buttonPushCounter == 0){
   analogWrite(FET_pin, 0);
   analogWrite(LED_pin, 0);
   }

//only switches on if the temperature is lower then the threshold
 if (buttonPushCounter == 1){
    analogWrite(FET_pin,255);
    analogWrite(LED_pin,255);   
   }


if (buttonPushCounter == 2){
    buttonPushCounter=0;
}


//swith off heating if temperature threshold is reached
if (buttonPushCounter == 1 and (N_temperature > maxTemp or P_temperature > maxTemp)){
  for (int i = 0; i <= 10; i++) {
        analogWrite(LED_pin, 0);
        delay(100);
        analogWrite(LED_pin, 255);
        delay(100);       
      }
     buttonPushCounter=0;
}


      
//swith off heating in case of thermistor error
if (buttonPushCounter == 1 and (N_temperature < 0 or P_temperature < 0)){
    for (int i = 0; i <= 10; i++) {
        analogWrite(LED_pin, 0);
        delay(500);
        analogWrite(LED_pin, 255);
        delay(500);       
      }
     buttonPushCounter=0;
}

}

Sketch uses 2380 bytes (232%) of program storage space. Maximum is 1024 bytes.
Global variables use 20 bytes (31%) of dynamic memory, leaving 44 bytes for local variables. Maximum is 64 bytes.

The strange thing is that tha last 2 if statements makes to code too big.

If I remove these lines from the code, it needs only 438 bytes

//swith off heating if temperature threshold is reached
if (buttonPushCounter == 1 and (N_temperature > maxTemp or P_temperature > maxTemp)){
  for (int i = 0; i <= 10; i++) {
        analogWrite(LED_pin, 0);
        delay(100);
        analogWrite(LED_pin, 255);
        delay(100);       
      }
     buttonPushCounter=0;
}


      
//swith off heating in case of thermistor error
if (buttonPushCounter == 1 and (N_temperature < 0 or P_temperature < 0)){
    for (int i = 0; i <= 10; i++) {
        analogWrite(LED_pin, 0);
        delay(500);
        analogWrite(LED_pin, 255);
        delay(500);       
      }
     buttonPushCounter=0;
}

avrdude: 438 bytes of flash written

I do not see any reason why these few lines needs much more space than the whole code itself.

Any suggestions?

As a final solution I will use an Attiny85.

I suspect that without those lines, the compile/link is "optimizing" away calculations whose results are never used.

Fitting floating point calcs into 1K is ... unlikely to work.
I count over 1024 bytes just for add/mul/div and a few smaller functions:

00000b2c 0000001c T __fp_mpack
00000950 00000022 T __fp_round
00000972 00000044 T __fp_split3
000008da 00000048 T __fp_cmp
00000b48 0000004a T __fp_powser
00000860 0000007a T __floatunsisf
000009d6 0000008a T log
000006e2 000000c0 T __addsf3x
000007aa 000000cc T __divsf3x
00000a6c 000000d2 T __mulsf3x

(compiled for ATtiny85)

I would imagine it comes down to the intricacies of an optimizing compiler.

Without those two if statements, neither N_temperature nor P_temperature gets used after its value has been calculated.

Therefore there's no need to include any of the code that calculates their values either.

Poof, most of your program gets omitted. Hence, it's much, much smaller.

are you sure about the conversion equation. I get the following

the division probably requires a lot of code
can you use a piecewise linear approximation?

output

      1  -81.00
     21  -45.00
     41  -35.00
     61  -27.00
     81  -22.00
    101  -19.00
    121  -15.00
    141  -12.00
    161  -9.00
    181  -6.00
    201  -4.00
    221  -2.00
    241  0.00
    261  2.00
    281  4.00
    301  5.00
    321  8.00
    341  9.00
    361  11.00
    381  13.00
    401  15.00
    421  17.00
    441  18.00
    461  20.00
    481  22.00
    501  24.00
    521  25.00
    541  27.00
    561  29.00
    581  31.00
    601  33.00
    621  34.00
    641  37.00
    661  39.00
    681  41.00
    701  43.00
    721  46.00
    741  48.00
    761  51.00
    781  53.00
    801  57.00
    821  59.00
    841  63.00
    861  67.00
    881  72.00
    901  77.00
    921  83.00
    941  91.00
    961  101.00
    981  116.00
   1001  143.00
   1021  166.00
struct Temp {
    int   adc;
    int   tempC;
}
tbl [] = {
    {      0,    -83 },
    {     16,    -48 },
    {     32,    -38 },
    {     48,    -31 },
    {     64,    -26 },
    {     80,    -22 },
    {     96,    -19 },
    {    112,    -16 },
    {    128,    -13 },
    {    144,    -11 },
    {    160,     -9 },
    {    176,     -6 },
    {    192,     -4 },
    {    208,     -3 },
    {    224,     -1 },
    {    240,      0 },
    {    256,      2 },
    {    272,      3 },
    {    288,      5 },
    {    304,      6 },
    {    320,      8 },
    {    336,      9 },
    {    352,     11 },
    {    368,     12 },
    {    384,     14 },
    {    400,     15 },
    {    416,     17 },
    {    432,     18 },
    {    448,     19 },
    {    464,     21 },
    {    480,     22 },
    {    496,     24 },
    {    512,     25 },
    {    528,     26 },
    {    544,     28 },
    {    560,     29 },
    {    576,     31 },
    {    592,     32 },
    {    608,     34 },
    {    624,     35 },
    {    640,     37 },
    {    656,     39 },
    {    672,     40 },
    {    688,     42 },
    {    704,     44 },
    {    720,     46 },
    {    736,     48 },
    {    752,     50 },
    {    768,     52 },
    {    784,     54 },
    {    800,     57 },
    {    816,     59 },
    {    832,     62 },
    {    848,     65 },
    {    864,     68 },
    {    880,     72 },
    {    896,     76 },
    {    912,     81 },
    {    928,     86 },
    {    944,     93 },
    {    960,    101 },
    {    976,    111 },
    {    992,    127 },
    {   1008,    157 },
    {   1024,    169 },
};
const int Ntemp = sizeof(tbl)/sizeof(Temp);

// -----------------------------------------------------------------------------
float
getTempC (
    int  adc )
{
    int n;
    for (n = 1; n < Ntemp; n++)
        if (adc < tbl [n].adc)
            break;
    n--; 

    int dx = tbl [n+1].adc - tbl [n].adc;
    int dy = tbl [n+1].tempC - tbl [n].tempC;

    return tbl [n].tempC + dy * (adc - tbl [n].adc) / dx;
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);

    for (int adc = 1; adc < 1024; adc += 20)  {
        char s [90];
        sprintf (s, " %6d  ", adc);
        Serial.print   (s);
        Serial.println (getTempC (adc));
    }
}

// -----------------------------------------------------------------------------
void loop () { }

Why worry about any of the intermittent values? The only thing you need to know is what input value will satisfy the two conditions tests, temperature > maxTemp and temperature < 0. Determine the analog input values to satisfy those conditions, and no calculations or table are needed.

The first thing to optimize is always the logic.

Do the calculation offline in a #define and use the result in your if statement.