3 ms·
You absolutely can do that in Rust. Rust has raw pointers, and they can be used just like C. It might look something like: *GPIO |= 1; Where GPIO is a poi
by nicoburns 3y ago
You absolutely can do that in Rust. Rust has raw pointers, and they can be used just like C. It might look something like:
*GPIO |= 1;
Where GPIO is a pointer that's mapped to a register.
There's almost certainly some Rust code doing just that somewhere down the call stack in your code above. You just don't get a lot of the safety benefits that come with Rust if you do it like that (although you do get some), so a lot of the library ecosystem has invested in higher level wrappers.
The motivation for doing so is good, but IMO it's been taken a little too far and led to things being over-abstracted. I suspect this will even itself out as embedded Rust matures.
- Measter 3y agoA few years ago, just after rustc got AVR support, I decided it'd be fun to port a (very) simplistic roguelike, writing everything from the HAL up. What I ended up doing was representing the MMIO registers and their bits using unit structs, and then defining and implementing some traits to tie it all together. I ended up with usage code looking like this (configuring the i2c bus): // Set the SDA and SCL pins to input, and enable the internal pullups. DDRC::clear_bits(DDRC::DDRC4 | DDRC::DDRC5); PORTC::set_bits(PORTC::PORTC4 | PORTC::PORTC5); // Initiliazing the prescaler to 1, and bit rate for a 400KHz transmission rate. TWSR::clear_bits(TWSR::TWPS0 | TWSR::TWPS1); TWBR::set_raw_value(TWI_BIT_RATE); // Enable the TWI module, and the ACK. TWCR::set_value(TWCR::TWEN | TWCR::TWEA); While my representation doesn't protect against races or aliased access, I did manage to get it to protect against reading write-only bits, writing read-only bits, and using bits with the wrong register, all at compile time. The error messages were a bit unpleasant, but I was quite happy with how it turned out. I could have implemented the *Assign operators for the register structs, but I'm not a huge fan of those. I feel it's a bit too opaque and error-prone, and preferred the clear function names. One thing that complicates matters is that you need to do volatile read and writes, not just standard pointer access. So using raw pointers, while possible, actually becomes kinda verbose.
- xinayder 3y agoThis is the whole point the author was trying to make. As you mentioned and made clear, the implementations in other languages barely have any checks for memory safety. In Rust, you can do that but you have to write a verbose code. Why not just abstract this on the SDK level and provide a way so that if you call *GPIO |= 1; it will already do that for you? Or as others mentioned, make a macro? I believe this is the point the author was trying to make. It's not about the niceties Rust have that make it complicated, it's the fact that you do have to write a whole lot more code for a simple task.