|
Lots of people pointing out that Rust isn't very ergonomic on embedded platforms. IMO one huge issue is how verbose the syntax needs to be. Look at some of the cases in the article, such as: let mut dp = pac::Peripherals::take().unwrap();
dp.RCC.ahb2enr.modify(|_, w| w.gpioaen().set_bit());
In C that would be: RCC->AHBENR2 |= RCC_AHBENR2_GPIOAEN;
Okay, you only have to take ownership of the Peripherals object once, but what about when they want to set a UART register in a function? Rust wants mutable pointers to have a trail of ownership outside of 'unsafe' blocks, so now we need: pub fn setup_transmission(regs: &mut R, [...])
where R: Deref<Target = pac::usart1::RegisterBlock> {
[...]
regs.cr2.modify(|_, w| w.stop().bits(config.stop_bits as u8));
[...]
}
This is a bit of a construction, in C(++) we can just do something like: void setup_transmission([...]) {
[...]
USART1->CR2 &= ~(USART_CR2_STOP_BITS);
USART1->CR2 |= ((uint8_t)config.stop_bits << USART_CR2_STOP_BITS_Pos);
[...]
}
The Rust snippet seems like it would be safer in a multi-threaded environment like an RTOS, or in cases where interrupts might modify peripheral registers, but...there are so many syntactical details to remember.I really tried to like embedded Rust, and I still think it compares favorably with the sort of C HALs that most chip manufacturers distribute. But the syntax seems to get in the way of quick simple access to peripheral registers. |