After figuring out how to unit test hardware registers for single reads and writes, we encounter code that makes multiple writes to a register. For example, here is some code that runs on 68HC12 microprocessor:
void set_pulse_speed(unsigned int ps) { SPI0DR = (unsigned char)(ps >> 8); // Pump speed high byte while( (SPI0SR & 0x80) == 0 ) {}; c = SPI0DR; // dummy read to reset the SPI interrupt flag SPI0DR = (unsigned char)ps; // Pump speed low byte while( (SPI0SR & 0x80) == 0 ) {}; c = SPI0DR; // dummy read to reset the SPI interrupt flag select_SPI_device(SPI_NONE); }
Since the code writes to the register SPI0DR two times, we cannot test the code by reading the last value written to SPI0DR. We obviously have to remember the "history" of all writes. This code saves consecutive writes, by defining the register as an array buffer:
// mock_registers.h extern unsigned char REG_write[16]; extern int REG_write_idx; #define reset_REG_write_idx() (REG_write_idx = 0) #define REG REG_write[++REG_write_idx] // my_code.c // Accessing REG more than once within a function REG = 7; // resolves to: REG_write[0] = 7; REG =55; // resolves to: REG_write[1] = 55; // unit_test_my_code.c reset_REG_write_idx(); // Reset array counter my_code(); // ... REG = 7; REG = 55; ... test_char_equal( 5, REG_write[0] ); // Verify that correct values are set test_char_equal( 77, REG_write[1] );
This code works great for a few tests. But when running hundreds of tests, some tests might access REG more than 16 times (the length of REG_write[16]). Thus I use this safer code that uses a circular buffer:
// mock_registers.h extern unsigned char REG_write[16]; extern int REG_write_idx; #define reset_REG_write_idx() (REG_write_idx = 0) #define REG if( ++REG_write_idx>=16 ) REG_write_idx=0; \ REG_write[REG_write_idx] REG = 7; // resolves to: // if( ++REG_write_idx>=16 ) REG_write_idx=0; // REG_write[REG_write_idx] = 7;
Testing functions that perform multiple reads from a register can be done in the same manner.