The CircuitPython runtime provides a wealth of support for adding modules in C. As mentioned, documentation is sparse and the best way to learn what you need is to explore the modules that are already present.
This guide provides an overview of what's involved in writing a port independant module in C. You are not limited in what you can add in this way. CircuitPython provides what you need to interface with most hardware you will want, but puts limits on the performance of your code. There are times you will want to use algorithms that benefit from very high performance. Implementing them in C and exposing them as Python modules is a way to get that level of performance.
There is also a way to add modules that rely on specific board capabilities. We'll explore that in a future quide.