How to approach an complex Arduino Uno project (Serial, SPI, Ethernet) in pure C, without libraries?
As Hans Neve wrote, you should really refer to the docs.

This is how it works in real life, when you want to write a driver for a new piece of HW.

You have to at least understand the block diagram, programming models and register sets of the device you want to control.

Then read whatever existing code you might find. In the practical case you have the driver for the version N-1 of the HW. Or maybe for something close enough.

As generic programming advice goes:


avoid any dynamic memory allocation, you will thank yourself later on, when you do not have to debug unexplained memory issues
if you want to write a driver, consider making it reentrant, should the same code be shared across multiple IP blocks
if you want to use OOP, avoid anything that requires runtime lookup. The compiler should have enough information to resolve everything statically.


WRT debugging: both device drivers might suffer from interference if you try to use the serial port. Consider using some ICD tools, like the AVR Dragon. Alternatively, you might find that debugging over I2C is less penalizing. But you have to define your debugging messages.