The type system in C allows you declare the pins as enums with literal bitmaps and declare functions that take only those enums to perform logical bitwise operations.
Trouble is, the libraries that (probably) came with your system (ESP32, or whatever) have these things defined as macros.
Still, you can have this type of type-safety at this level, and get compile-time errors when doing the wrong thing.
> Fifteen minutes later, it caught another error: by sharing the SPI bus, it could identify that there were more than two devices connected, because there were two CS pins declared, and because the device wasn't exclusive, I had to wrap the bus in a refcell for memory safety.
This is also something that can be done within the C typing system so that you get compile-time errors.
> I never thought that embedded programming could be fun, and strong types were what changed my mind.
Good for you. You should note, however, that none of these two scenarios you listed are specific to Rust - you could have solved both those issues by leaning on the typing guarantees already in C.
A big problem is that using the escape hatches in C to break the typing guarantees are not really frowned upon, so much of the code you see does extra work to break the typing.
And then newbies come along, look at the code that does extra work to break the type system, and conclude that the type system can't prevent some class of problems.
The reality is that, until and unless you put in the extra effort to break the typing (such as throwing around casted void pointers), you will get quite a lot of compiler errors when you mismatch types in C.