Ground Embedded KO Subscribe

Notes / Firmware Design & Quality

Modules and interfaces: drawing boundaries with headers

The .h shows only what the outside should see, and the .c hides the inside. How to design a module with static, opaque types and an init function.

GROUND EMBEDDED · NOTEFirmware Design & Quality 02Modules and interfaces 1volatile uint32_t *ODR 2 = (uint32_t*)0x40020014; 3*ODR |= (1u << 5); 4while (1) { 5 if (flag) toggle(); 6}

The shape of a good module

Other modulesmotor.ha few public functionsmotor.cstatic variables, internals
From outside a module, only the functions in its header are visible. Internal variables are hidden with static.
/* motor.h : only what the outside should see */
typedef enum { MOTOR_OK, MOTOR_FAULT } motor_status_t;
void motor_init(void);
void motor_set_duty(int16_t duty_permille);   // -1000 to 1000
motor_status_t motor_status(void);
/* motor.c : the inside */
static int16_t s_duty;            // cannot be touched from outside
static void apply_pwm(void) { ... }

Principles

  • Do not expose global variables with extern; read and write them through functions. Range checks and logging can then live in one place.
  • static on internal functions and variables
  • State the unit in the name or a comment: duty_permille, speed_rpm, current_mA
  • A header compiles by itself (it includes what it needs)
  • One module, one responsibility: "motor driver" and "speed control" are separate modules

Write the interface first

Write the header before the implementation and agree it with the team, and others can start developing and testing against that interface before the implementation is finished.

FREE PDFGet the 3 free ebooksIf you want to keep reading this topic as one book: BLDC motor control, serial communication and sensors at book length. PDFs are in Korean.Get them free →