/* Read the angle register (ANGLECOM) */
angle = spi_write(0xFFFF);
/* Read the angle register */
angle = spi_write(A_READ | A_PARITY_1 | A_ANGLECOMREG);
Now, you don't have to understand exactly what's going on here (and the actual process of reading an angle from the AS5147 rotary position sensor is a little bit more complicated), but I am trying to make a point.
I would argue that the second code snippet is a waste of time. (Some presumptions here: You had to define A_READ, A_PARITY_1 and A_ANGLECOMREG).
But, why would I advocate the hard coded version?
- The chip (AS5147) isn't going to change SPI command structure anytime during its production cycle.
- If you choose a new chip, you are going to have to study it and figure out the hard coded values anyway.
- The abstraction in the 2nd code snippet is going to only work for this exact chip.
- You have to work out the bit twiddling anyway (to come up with A_READBIT, etc)
- 0xFFFF is what you will see in your debugger
- It is *always* 0xFFFF
- Ease of modification doesn't work here. If you go "oh, that should be A_PARITY_0" and change it (without verifying the actual resulting write value, it is going to cause a lot of debugging woes).
This is sort of an argument between "ease of writing" vs "ease of debugging" and in embedded development, "ease of debugging" is what you are really shooting for (or maybe call it "ease of validation").
I see the same thing happening with STM32's HAL or StdPeriph. There is a focus on making it easier to load up registers (often taking 1 line of register loading code and stretching it into multiple lines of structure loading using verbose enums/types you have to look up).
To be honest, when I work in Forth on the STM32, I don't have such luxuries and my program is full of well documented hex and binary register banging.