This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

The impact of one huge header file

Hello,
Somebody here insists that all the program's definitions will be stored in one large header file that all C modules include, rather that keeping the declarations distributed among specific header files. That sounds pretty crappy to me - but how bad it is really? will it have a very negative impact on build time?

Parents
  • I'm at home today, so no access to real Keil code.

    Anyway, I put together some demo examples - not compileable since it is incomplete and I invented from memory :)

    A general file "general.h" that is included by every single source file.

    /**
     * \file general.h
     * \brief Project-specific main include file
     *
     * Handles global constants and data types, and some project configurations
     */
    
    enum {
        VERSION_MAJOR   = 1,    ///< Stepped on incompatibility changes or big
                                ///< rewrites. 0 before initial release.
        VERSION_MINOR   = 0,    ///< Stepped on additions of new functionality.
                                ///< Initial value: 0 whenever major is stepped.
        VERSION_FIX     = 1,    ///< Stepped for bug-fixes.
                                ///< Initial value: 1 whenever major or minir is
                                ///< stepped.
    };
    
    // Some quick-to-modify global configuration options.
    enum {
        COM0_BAUD       = 19200,    ///< Baud-rate for monitor port.
        COM0_RX_BUFFER  = 256,      ///< Must be 2^n
        COM0_TX_BUFFER  = 8192,     ///< Must be 2^n
        COM1_BAUD       = 9600,     ///< Baud rate for RFID port.
        COM1_RX_BUFFER  = 32,       ///< Must be 2^n
        COM1_TX_BUFFER  = 32,       ///< Must be 2^n
    
        CPU_CRYSTAL     = 20,       ///< Crystal frequency in MHz.
        CPU_CORE_SPEED  = 48,       ///< Core speed in MHz
        CPU_PCLK        = 12,       ///< Default peripherial clock 12 MHz
    
        SSP0_PCLK       = 12,
        SSP0_RX_BUFFER  = 64,       ///< Must be 2^n
        SSP0_TX_BUFFER  = 64,       ///< Must be 2^n
    };
    
    #define SSP0_EXTRA_DEBUG 0
    #define SSP1_EXTRA_DEBUG 0
    #define ADC0_EXTRA_DEBUG 0
    #define FFT_EXTRA_DEBUG 0
    #define REGRESSION_BUILD 0
    
    // Maybe we don't have stdint.h support available from the compiler...
    typedef unsigned char uint8_t;
    typedef unsigned short uint16_t;
    typedef unsigned int uint32_t;
    typedef unsigned long long uint64_t;
    
    // Capabilities may vary depending on mounted variant.
    #if TARGET_CPU==2364
    #  define TARGET_LPC2364
    #  include <lpc23xx.h>
    #  include "lpc2364.h"
    #elif TARGET_CPU==2366
    #  define TARGET_LPC2366
    #  include <lpc23xx.h>
    #  include "lpc2366.h"
    #else
    #  error "Target CPU not defined"
    #endif
    
    // Capabilities and pin allocations may vary between hardware revisions.
    #if !defined(TARGET_REVISION)
    #  error "No target revision defined"
    #elif TARGET_REVISION==0
    #  include "defines_hwrev_0.h"
    #elif TARGET_REVISION==1
    #  include "defines_hwrev_1.h"
    #else
    #  error "Unknown target revision"
    #endif
    
    // Some includes every module should have.
    #include "config.h"
    
    // Some global variables.
    extern volatile uint32_t uptime_1s;     ///< Uptime in 1s resolution.
    extern volatile uint32_t uptime_1ms;    ///< Uptime in 1ms resolution.
    
    // Some misc functions generally available.
    int mon_printf(const char* fmt,...);
    const char* get_version_string(void);
    uint32_t get_app_area_crc(void);
    uint32_t get_config_area_crc(void);
    uint16_t crc16(uint16_t crc,const uint8_t data[],unsigned size);
    uint32_t crc32(uint32_t crc,const uint8_t data[],unsigned size);
    

    I may have a target-specific header file ssp_23xx.h that defines constants for the SSP (NXP LPC23xx name for the high-speed SPI):

    /**
     * \file ssp_23xx.h
     * \brief Register descriptions for NXP LPC23xx SSP device.
     */
    
    /// \brief Flags for the SSPxCR0 register
    enum {
        SSPCR0_DSS_4BIT         = 0x0003,   ///< 4-bit transfers
        ...
        SSPCR0_DSS_16IT         = 0x000f,   ///< 16-bit SPI transfers
        SSPCR0_FRF_SPI          = 0x0000,   ///< Frame Format: SPI
        SSPCR0_FRF_TI           = 0x0010,   ///< Frame Format: TI
        SSPCR0_FRF_MICROWIRE    = 0x0020,   ///< Frame Format: Microwire
        SSPCR0_CPOL_IDLE_LOW    = 0x0000,   ///< Keep clock low in idle
        SSPCR0_CPOL_IDLE_HIGH   = 0x0040,   ///< Keep clock high in idle
        SSPCR0_CPHA_LEADING     = 0x0000,   ///< Capture data on leading flank of clock
        SSPCR0_CPHA_TRAILING    = 0x0080,   ///< Capture data on trailing flank of clock
        SSPCR0_SCR_SHIFT        = 8,        ///< Bit offset of this field
        SSPCR0_SCR_MASK         = 0xff00    ///< Mask to extract this field
    };
    
    /// \brief Flags for the SSPxCR1 register
    enum {
        SSPCR1_LBM_OFF          = 0x0000,   ///< Loop-back mode off
        SSPCR1_LBM_ON           = 0x0001,   ///< Loop-back mode on
        SSPCR1_SSE_DISABLED     = 0x0000,   ///< SSP controller disabled
        SSPCR1_SSE_ENABLED      = 0x0002,   ///< SSP controller enabled
        SSPCR1_MS_MASTER        = 0x0000,   ///< Master/Slave: Master
        SSPCR1_MS_SLAVE         = 0x0004,   ///< Master/Slave: Slave
        SSPCR1_SLAVE_OUTPUT_ON  = 0x0000,   ///< Slave side read/write - driving MISO line
        SSPCR1_SLAVE_OUTPUT_OFF = 0x0008,   ///< Slave side read-only - not driving MISO line
    };
    

    And then a project-specific file ssp0.h that declare accessor functions. The level of the functions may vary from project to project. Some projects have raw read and write functions, while some projects are using buffered (possibly filtering) API functions, or even a complete protocol manager that take message data as input and transparently converts into device-transmittable packets:

    /**
     * \file ssp0.h
     * \brief Accessor functions for SPI communication on ssp0.
     */
    
    // Some statistics
    extern uint32_t ssp0_irq_count;     ///< # of SSP0 interrupts.
    extern uint32_t ssp0_tx_count;      ///< # of transmitted bytes.
    extern uint32_t ssp0_rx_count;      ///< # of received bytes.
    extern uint32_t ssp0_rx_overflows;  ///< # of detected RX FIFO overflows.
    
    void ssp0_init(void);
    void ssp0_deinit(void);
    void ssp0_send(uint8_t v);
    void ssp0_send_block(uint8_t data[],unsigned count);
    unsigned ssp0_idle(void);
    unsigned ssp0_have_rx_data(void);
    int ssp0_recv(void);
    int ssp0_recv_block(uint8_t data[],unsigned max_count);
    

    Then I have the implementation of the support for the SSP0 device:

    /**
     * \file ssp0.c
     * \brief Implements ssp0 functionality
     */
    
    #include "general.h"        // Some eneric data types, debug flags, ...
    #include "ssp_23xx.h"       // Processor-specific declarations for the SSP device
    #include "ssp0.h"           // Exported declarations for this module
    
    // Some configuration options for this module
    enum {
        SSP0CR0_SCR = xxx;      ///< What bit-rate to run the device in.
    };
    
    void ssp0_init(void) {
        // Should run in 16-bit mode SPI with clock idle low and sampling of falling edge.
        // Bit-rate defined at top of file.
        SSP0CR0 = SSPCR0_DSS_16BIT | SSPCR0_FRF_SPI | SSPCR0_CPOL_IDLE_LOW | SSPCR0_CPHA_TRAILING | SSP0CR0_SCR;
    
        // Run as master
        SSP0CR1 = SSPCR1_LBM_OFF | SSPCR1_SSE_DISABLED | SSPCR1_MS_MASTER;
    
        ...
    
        SSP0CR1 |= SSPCR1_SSE_ENABLED;  // Fully initialized - enable the device
    }
    

Reply
  • I'm at home today, so no access to real Keil code.

    Anyway, I put together some demo examples - not compileable since it is incomplete and I invented from memory :)

    A general file "general.h" that is included by every single source file.

    /**
     * \file general.h
     * \brief Project-specific main include file
     *
     * Handles global constants and data types, and some project configurations
     */
    
    enum {
        VERSION_MAJOR   = 1,    ///< Stepped on incompatibility changes or big
                                ///< rewrites. 0 before initial release.
        VERSION_MINOR   = 0,    ///< Stepped on additions of new functionality.
                                ///< Initial value: 0 whenever major is stepped.
        VERSION_FIX     = 1,    ///< Stepped for bug-fixes.
                                ///< Initial value: 1 whenever major or minir is
                                ///< stepped.
    };
    
    // Some quick-to-modify global configuration options.
    enum {
        COM0_BAUD       = 19200,    ///< Baud-rate for monitor port.
        COM0_RX_BUFFER  = 256,      ///< Must be 2^n
        COM0_TX_BUFFER  = 8192,     ///< Must be 2^n
        COM1_BAUD       = 9600,     ///< Baud rate for RFID port.
        COM1_RX_BUFFER  = 32,       ///< Must be 2^n
        COM1_TX_BUFFER  = 32,       ///< Must be 2^n
    
        CPU_CRYSTAL     = 20,       ///< Crystal frequency in MHz.
        CPU_CORE_SPEED  = 48,       ///< Core speed in MHz
        CPU_PCLK        = 12,       ///< Default peripherial clock 12 MHz
    
        SSP0_PCLK       = 12,
        SSP0_RX_BUFFER  = 64,       ///< Must be 2^n
        SSP0_TX_BUFFER  = 64,       ///< Must be 2^n
    };
    
    #define SSP0_EXTRA_DEBUG 0
    #define SSP1_EXTRA_DEBUG 0
    #define ADC0_EXTRA_DEBUG 0
    #define FFT_EXTRA_DEBUG 0
    #define REGRESSION_BUILD 0
    
    // Maybe we don't have stdint.h support available from the compiler...
    typedef unsigned char uint8_t;
    typedef unsigned short uint16_t;
    typedef unsigned int uint32_t;
    typedef unsigned long long uint64_t;
    
    // Capabilities may vary depending on mounted variant.
    #if TARGET_CPU==2364
    #  define TARGET_LPC2364
    #  include <lpc23xx.h>
    #  include "lpc2364.h"
    #elif TARGET_CPU==2366
    #  define TARGET_LPC2366
    #  include <lpc23xx.h>
    #  include "lpc2366.h"
    #else
    #  error "Target CPU not defined"
    #endif
    
    // Capabilities and pin allocations may vary between hardware revisions.
    #if !defined(TARGET_REVISION)
    #  error "No target revision defined"
    #elif TARGET_REVISION==0
    #  include "defines_hwrev_0.h"
    #elif TARGET_REVISION==1
    #  include "defines_hwrev_1.h"
    #else
    #  error "Unknown target revision"
    #endif
    
    // Some includes every module should have.
    #include "config.h"
    
    // Some global variables.
    extern volatile uint32_t uptime_1s;     ///< Uptime in 1s resolution.
    extern volatile uint32_t uptime_1ms;    ///< Uptime in 1ms resolution.
    
    // Some misc functions generally available.
    int mon_printf(const char* fmt,...);
    const char* get_version_string(void);
    uint32_t get_app_area_crc(void);
    uint32_t get_config_area_crc(void);
    uint16_t crc16(uint16_t crc,const uint8_t data[],unsigned size);
    uint32_t crc32(uint32_t crc,const uint8_t data[],unsigned size);
    

    I may have a target-specific header file ssp_23xx.h that defines constants for the SSP (NXP LPC23xx name for the high-speed SPI):

    /**
     * \file ssp_23xx.h
     * \brief Register descriptions for NXP LPC23xx SSP device.
     */
    
    /// \brief Flags for the SSPxCR0 register
    enum {
        SSPCR0_DSS_4BIT         = 0x0003,   ///< 4-bit transfers
        ...
        SSPCR0_DSS_16IT         = 0x000f,   ///< 16-bit SPI transfers
        SSPCR0_FRF_SPI          = 0x0000,   ///< Frame Format: SPI
        SSPCR0_FRF_TI           = 0x0010,   ///< Frame Format: TI
        SSPCR0_FRF_MICROWIRE    = 0x0020,   ///< Frame Format: Microwire
        SSPCR0_CPOL_IDLE_LOW    = 0x0000,   ///< Keep clock low in idle
        SSPCR0_CPOL_IDLE_HIGH   = 0x0040,   ///< Keep clock high in idle
        SSPCR0_CPHA_LEADING     = 0x0000,   ///< Capture data on leading flank of clock
        SSPCR0_CPHA_TRAILING    = 0x0080,   ///< Capture data on trailing flank of clock
        SSPCR0_SCR_SHIFT        = 8,        ///< Bit offset of this field
        SSPCR0_SCR_MASK         = 0xff00    ///< Mask to extract this field
    };
    
    /// \brief Flags for the SSPxCR1 register
    enum {
        SSPCR1_LBM_OFF          = 0x0000,   ///< Loop-back mode off
        SSPCR1_LBM_ON           = 0x0001,   ///< Loop-back mode on
        SSPCR1_SSE_DISABLED     = 0x0000,   ///< SSP controller disabled
        SSPCR1_SSE_ENABLED      = 0x0002,   ///< SSP controller enabled
        SSPCR1_MS_MASTER        = 0x0000,   ///< Master/Slave: Master
        SSPCR1_MS_SLAVE         = 0x0004,   ///< Master/Slave: Slave
        SSPCR1_SLAVE_OUTPUT_ON  = 0x0000,   ///< Slave side read/write - driving MISO line
        SSPCR1_SLAVE_OUTPUT_OFF = 0x0008,   ///< Slave side read-only - not driving MISO line
    };
    

    And then a project-specific file ssp0.h that declare accessor functions. The level of the functions may vary from project to project. Some projects have raw read and write functions, while some projects are using buffered (possibly filtering) API functions, or even a complete protocol manager that take message data as input and transparently converts into device-transmittable packets:

    /**
     * \file ssp0.h
     * \brief Accessor functions for SPI communication on ssp0.
     */
    
    // Some statistics
    extern uint32_t ssp0_irq_count;     ///< # of SSP0 interrupts.
    extern uint32_t ssp0_tx_count;      ///< # of transmitted bytes.
    extern uint32_t ssp0_rx_count;      ///< # of received bytes.
    extern uint32_t ssp0_rx_overflows;  ///< # of detected RX FIFO overflows.
    
    void ssp0_init(void);
    void ssp0_deinit(void);
    void ssp0_send(uint8_t v);
    void ssp0_send_block(uint8_t data[],unsigned count);
    unsigned ssp0_idle(void);
    unsigned ssp0_have_rx_data(void);
    int ssp0_recv(void);
    int ssp0_recv_block(uint8_t data[],unsigned max_count);
    

    Then I have the implementation of the support for the SSP0 device:

    /**
     * \file ssp0.c
     * \brief Implements ssp0 functionality
     */
    
    #include "general.h"        // Some eneric data types, debug flags, ...
    #include "ssp_23xx.h"       // Processor-specific declarations for the SSP device
    #include "ssp0.h"           // Exported declarations for this module
    
    // Some configuration options for this module
    enum {
        SSP0CR0_SCR = xxx;      ///< What bit-rate to run the device in.
    };
    
    void ssp0_init(void) {
        // Should run in 16-bit mode SPI with clock idle low and sampling of falling edge.
        // Bit-rate defined at top of file.
        SSP0CR0 = SSPCR0_DSS_16BIT | SSPCR0_FRF_SPI | SSPCR0_CPOL_IDLE_LOW | SSPCR0_CPHA_TRAILING | SSP0CR0_SCR;
    
        // Run as master
        SSP0CR1 = SSPCR1_LBM_OFF | SSPCR1_SSE_DISABLED | SSPCR1_MS_MASTER;
    
        ...
    
        SSP0CR1 |= SSPCR1_SSE_ENABLED;  // Fully initialized - enable the device
    }
    

Children
No data