Unit Testing code that touches the HW registers

 This article guides you on how to unit-test code that reads or writes hardware registers of your SJ development board.

// Typical code

int get_ultrasonic_pulse_width(void) {

 // Send a pulse width

 LPC_GPIO1->CLR = (1 << 2);

 delay_us(10);

 LPC_GPIO1->SET = (1 << 2);

 

 const uint32_t previous = time_now();

 while (LPC_GPIO1->PIN & (1 << 3)) {

 ;

 }

 

 return time_delta(previous);

}

Before we solve the problem, let us write better code that is self expressive and does not require comments to understand its intent.

static void send_pulse_to_ultrasonic(void) {

 const uint32_t ultrasonic_pulse_pin = (1 << 2);

 LPC_GPIO1->CLR = ultrasonic_pulse_pin;

 delay_us(10);

 LPC_GPIO1->SET = ultrasonic_pulse_pin;

}

static void wait_for_ultrasonic_pulse_to_bounce_back() {

 while (LPC_GPIO1->PIN & (1 << 3)) {

 ;

 }

}

// Notice the clarity of this function compared to the previous code snippet

int get_ultrasonic_pulse_width(void) {

 send_pulse_to_ultrasonic();

 

 const uint32_t previous = time_now();

 wait_for_ultrasonic_pulse_to_bounce_back();

 return time_delta(previous);

}

And the next level:

// Separate header file to abstract the hardware, such that we can mock out this API

// file: ultrasonic_pins.h

void ultrasonic_pins__set_pulse(bool true_for_logic_high);

bool ultrasonic_pins__get_input_pin_value(void);

#include "ultrasonic_pins.h"

static void send_pulse_to_ultrasonic(void) {

 // This can now move to ultrasonic_pins.c

 // const uint32_t ultrasonic_pulse_pin = (1 << 2);

 ultrasonic_pins__set_pulse(true);

 delay_us(10);

 ultrasonic_pins__set_pulse(false);

}

static void wait_for_ultrasonic_pulse_to_bounce_back() {

 while (ultrasonic_pins__get_input_pin_value()) {

 ;

 }

}

int get_ultrasonic_pulse_width(void) {

 send_pulse_to_ultrasonic();

 

 const uint32_t previous = time_now();

 wait_for_ultrasonic_pulse_to_bounce_back();

 return time_delta(previous);

}

