I am writing C code with multiple modules like LCD display, flash memory, and GSM module etc. The project consists of thousands of lines of code, in different files.The behavior of the system can be changed with run-time parameters (eg LCD brightness) using a buttons. And during compile time by redefining #define directives and const variables.Currently all of these variables and constants lie with the rest of the modules in their respective files. I am finding is very hard to maintain the settings without losing modularity.My question is two part:How do I make the compile time parameters more accessible? Moving all the variables to a separate file would certainly make life easier by making all the settings available in one place. Also some settings go in groups, so it makes more sense to change one #define in one file rather than fishing for many #defines in multiple files. But it does not seem right to destroy the modularity this way.I need to write code that will save all the runtime parameters  to flash memory, and retrieve them on reboot. Ideally this should be done in getter and setter functions. But the problem is that all the settings and configurations are stored in a sector in flash memory. A parameter can't just be rewritten without erasing the flash memory. So LCD module can't change its brightness without being aware of all the other parameters. It makes more sense to keep all the settings in a struct, but the cost is moving the variables away from the modules.What is the best way to tackle this problem without compromising on the readability and modularity of code.
How to maintain modularity in C?
programming practices;c;hardware
Placing all of the compile time switches into 1 central file makes finding and changing them easy.  That said, compile time switches can be confusing, particularly if there is a significant quantity of them.I worked on an embedded project where there were a few different boards to control different hardware, but had the same MCU, communication protocols, flash storage, and other similar properties.  Rather than use #defines to switch between building the different versions of firmware, I put all of the core modules into a Core directory and the board-specific modules into their own directories.  I setup the build process to build all versions of the firmware at once.  This helps prevents a breaking change when working on the Core component.Part of the same project involved saving various parameters to flash.  Each module that needed to write to flash had its own flash parameters struct, along with a unique entry in a moduleID enum.  When a module wanted to save its data, it would pass a pointer to the flash parameter struct, the size of the struct (in bytes), and  its moduleID to the flash storage module.The flash storage module just looks at the passed struct pointer as a chunk of memory.  It would copy the data into flash, and add a small header that contained the moduleID and the size of memory.  When a module wanted its data from flash, it would pass its moduleID to the flash storage module, and then the flash storage module would scan the flash block for the moduleID, load the data into RAM, and then return it to the calling param.  This way, the flash storage didn't need to know about who called it.  All it cared about was the moduleID passed to it and the size of the data it was handing.