1

I'm doing a small project with ESP32 board. When initializing a driver, multiple structs are passed to initialization functions. I know that there are two ways to store such structs:

  1. Storing structs on heap (with calloc or malloc)
adc_continuous_config_t cfg = calloc(1, sizeof(adc_continuous_config_t));

cfg->sample_freq_hz = 4500;
cfg->conv_mode = ADC_CONV_SINGLE_UNIT_1;
cfg->format = ADC_DIGI_OUTPUT_FORMAT_TYPE;

adc_continuous_config(*handle, cfg);
free(cfg);
  1. Storing structs on stack
adc_continuous_config_t cfg = {
    .sample_freq_hz = 4500,
    .conv_mode      = ADC_CONV_SINGLE_UNIT_1,
    .format         = ADC_DIGI_OUTPUT_FORMAT_TYPE1,
};

adc_continuous_config(*handle, &cfg)

I was wondering which approach is encouraged.

3
  • 1
    It depends on several details, like: What is the requested lifetime of the data? Will the data be reused later? Are the values of the structure known at compile time? And probably some more. So this question cannot be answered in general. Commented Jun 21, 2023 at 6:15
  • I think the struct is only used for driver initialization which will only happen once in the machine's lifetime which means it will not be reused until reboot. All the values of the struct are simply predefined constants so they are known at compile time. Commented Jun 21, 2023 at 17:44
  • Then go with Edgar's solution, placing the structure in flash memory. Commented Jun 21, 2023 at 18:58

1 Answer 1

2

You seem to be initializing this struct with constants. In such a case, I would use neither the heap nor the stack, but a third option: the “read-only data” section of the program. At global scope:

const adc_continuous_config_t cfg = {
    .sample_freq_hz = 4500,
    .conv_mode      = ADC_CONV_SINGLE_UNIT_1,
    .format         = ADC_DIGI_OUTPUT_FORMAT_TYPE1,
};

Rationale: The constants you are using to fill the struct have to be stored somewhere in the flash when the program is not running. Although I do not know the details of the machine language of the ESP32, it seems to me the compiler has only two options to compile your example code. It could say:

  • load a CPU register with the immediate value 4500
  • store that register at the address of cfg->sample_freq_hz
  • load a CPU register with the immediate value ADC_CONV_SINGLE_UNIT_1
  • etc.

Then the values are stored as immediate operands of machine instructions. The other option would be to store an anonymous version of the initialized struct in the read-only data section of the program, and issue a memcpy() to initialize the allocated space at run time.

If you instead store the initialized struct as a global constant, it will go straight into the read-only data section of the program (like in the second compiler strategy), and you will use it from there. No extra copy needed. No extra machine instruction for initializing space allocated on the heap or stack.

Caveat: I assume adc_continuous_config() expects its second parameter to be of type “pointer to const data”. If it expects it to be a pointer to modifiable data, then this will not work.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.