This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Is it normal that this function takes 7kB of code size?

Hello, I am programming nRF51 on Keil. My app uses BLE with softdevice S130, PWM, and I2C communication with two sensors. Also RTT for debugging.

I have already reached the limit code size of Keil with free license, 32kB. I am using Optimization level 0 because when I put 1 or higher mmy app doesn't work anymore, but that is another question I haven't had time to debug yet.

My question: is it normal that putting just one call in main loop to this function, using optimization level 0, code size increases from 28kB to 35kB (7kB difference!)?? Or I am doing something wrong?

Thank you very much for your time,

Luis Rodenas

This is the function (actually splitted in 2 functions):

uint32_t MS5611Read2(uint8_t CMD, uint8_t OSR)  // temperature data read
{
    uint8_t data[3] = {0,0,0  };
	uint32_t err_code;
	
	err_code = twi_write_single2((CMD | OSR), 1);
    APP_ERROR_CHECK(err_code);

  switch (OSR)
  {
  case ADC_256: 
		nrf_delay_ms(1);
    break;  // delay for conversion to complete
  case ADC_512: 
		nrf_delay_ms(3);
    break;
  case ADC_1024: 
		nrf_delay_ms(4);
    break;
  case ADC_2048: 
		nrf_delay_ms(6);
    break;
  case ADC_4096: 
		nrf_delay_ms(10);
    break;
  }

	twi_read_burst2(0x00, data, 3);

  return (uint32_t) (((uint32_t) data[0] << 16) | (uint32_t) data[1] << 8 | data[2]); // construct PROM data for return to main program
}

void ms5611_read2(){
   uint32_t D1 = 0, D2 = 0;  // raw MS5611 pressure and temperature data
   double dT, OFFSET, SENS, T2, OFFSET2, SENS2;  // First order and second order corrections for raw S5637 temperature and pressure data
	double Temperature, Pressure; // stores MS5611 pressures sensor pressure and temperature
    D1 = MS5611Read2(ADC_D1, OSR);  // get raw pressure value
    D2 = MS5611Read2(ADC_D2, OSR);  // get raw temperature value
    dT = D2 - Pcal[5]*pow(2,8);    // calculate temperature difference from reference
    OFFSET = Pcal[2]*pow(2, 16) + dT*Pcal[4]/pow(2,7);
    SENS = Pcal[1]*pow(2,15) + dT*Pcal[3]/pow(2,8);

    Temperature = (2000 + (dT*Pcal[6])/pow(2, 23))/100;           // First-order Temperature in degrees Centigrade

    // Second order corrections
    if(Temperature > 20) 
    {
      T2 = 0; // correction for high temperatures
      OFFSET2 = 0;
      SENS2 = 0;
    }
    if(Temperature < 20)                   // correction for low temperature
    {
      T2      = dT*dT/pow(2, 31); 
      OFFSET2 = 5*(100*Temperature - 2000)*(100*Temperature - 2000)/2;
      SENS2   = 5*(100*Temperature - 2000)*(100*Temperature - 2000)/4;
    } 
    if(Temperature < -15)                      // correction for very low temperature
    {
      OFFSET2 = OFFSET2 + 7*(100*Temperature + 1500)*(100*Temperature + 1500);
      SENS2 = SENS2 + 11*(100*Temperature + 1500)*(100*Temperature + 1500)/2;
    }
    // End of second order corrections
    //
    Temperature = Temperature - T2/100;
    OFFSET = OFFSET - OFFSET2;
    SENS = SENS - SENS2;

    Pressure = (((D1*SENS)/pow(2, 21) - OFFSET)/pow(2, 15))/100;  // Pressure in mbar or Pa/100

      float altitude = 145366.45*(1. - pow((Pressure/1013.25), 0.190284));


	char buffer [50];
	sprintf(buffer, "%f", altitude);
		SEGGER_RTT_WriteString(0, buffer);
    
}
  • From what I see you use e.g. function pow(...) which can include one or two kB itself from Keil lib (if this is the only place you call it). It also can easily be that some other function calls in this code are first and only one occurrence in your app and then they cause including whole modules (e.g. twi_write_single2(...) ?). By refactoring you might come back under 32kB but in general I'd say you are close to the point where you either need paid Keil license or set-up your project with GCC where you are unlimited (and e.g. for me even the best optimizations O3 and Os work, resulting code size is getting closer to Keil products - IAR is still better but that's another story and investment).

    Cheers Jan

  • Thanks endnode. I will surely consider migrating to GCC Eclipse. It is true that this the only place I use pow so far, so that adds size, but twi functions were already used for the other sensor, so I believe they were already added to the initial 28kB... Let's assume pow takes 2kB, is it normal that the rest consumes 5kB? (not taking into account twi functions which I think are already included before)

  • Using double arithmetic on a Cortex M0 means a whole heap of math libraries are going to be pulled in to emulate floating point. If you look at your map file you should see all the stuff you've caused to be linked.

    Is this calculation you need to do on the device, can't you send raw data and calculate on the other side where all the processing power is?

    I see you have sprintf() in there too, that's another load of code. It's less if you link with the nano-C library, I don't know how to do that with Keil, or if it does it anyway.

  • Well you can use GCC from command line (e.g. by cygwin) just for compilation, don't need to enter Eclipse nightmare (unless you love it;). To the code size analysis: the usual (and probably the only "right" way) is to compile project twice, once with this new code and second time without. Then compare MAP files (or some equivalent produced by Keil) and you will clearly see where your magic 7kB come from.

    Cheers Jan

  • Thank you for your comments. I tried cygwin but found it difficult (I am 100% beginner on this things). So finally I followed this tutorial devzone.nordicsemi.com/.../ and installed Eclipse + GCC. Very happy so far. :) I will of course reduce float operations, but I need some. Also my nRF51 is all the processing power I have, since I am building an standalone robot and need those calculations for autocontrol.

Related