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?
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 }