[HN Gopher] Learning Rust for Embedded Systems
       ___________________________________________________________________
        
       Learning Rust for Embedded Systems
        
       Author : tekkertje
       Score  : 57 points
       Date   : 2021-11-18 19:12 UTC (3 hours ago)
        
 (HTM) web link (www.embeddedrelated.com)
 (TXT) w3m dump (www.embeddedrelated.com)
        
       | nynx wrote:
       | We're using rust on STM32F1 chips as part of the electronics for
       | a liquid rocket engine that my university's SEDS chapter is
       | developing. Rust makes this all so much easier and quicker to
       | write.
        
       | kennywinker wrote:
       | I'm currently working on a product using rust on stm32 hardware.
       | I'm very thankful to be using rust instead of c/c++ for a variety
       | of reasons. That said, so far the big pain points so far have
       | been:
       | 
       | Each HAL implements different things, or the same thing in
       | different ways. I'm in the middle of switching from the stm32f1 i
       | started on to the more capable stm32f4 and it's been a painful
       | switch. I assume this would also suck in other languages, but it
       | seems fixable in rust. There's also widely varied support for
       | other MCUs
       | 
       | Lack of emulation. You can emulate an arm cpu in qemu, but
       | there's no tools for mocking out hardware - which means testing
       | has to happen on device (or you need to fragment your application
       | into qemu-testable pieces)
       | 
       | Shared memory / global initialization is overly complex. If you
       | have a resource (say a gpio pin) that you want to set up in main
       | but use in an interrupt and nowhere else, you have to use like
       | five layers of abstraction to "safely" do that.
        
         | jareklupinski wrote:
         | i'm not a Rust-er but I hope this really takes off
         | 
         | after trying to switch to Basic, then Embedded Lua, then
         | MicroPython, then TinyGo... I keep coming back to putting
         | together microcontroller code in C/++, every time
         | 
         | if even one language can break the barrier, there's hope :)
        
           | kennywinker wrote:
           | Since I was mostly complaining, it might not sound like it -
           | but I think that embedded Rust has arrived, for some MCUs. If
           | there is good support for your chosen chip / dev board -
           | there's no need to wait around for it to take off. You can
           | even link C/C++ code if you need to use a library that
           | doesn't have a rust equivalent.
        
         | kevin_thibedeau wrote:
         | The F1 series is the original STM32 and it has notable hardware
         | differences with the later family members that show up in the
         | HAL. While the API has its sore spots there really is no good
         | way for them to paper over all the differences between these
         | variants. Avoid selecting F1 if you need optimal forward and
         | cross compatibility. I'd also point out that the newer LL
         | driver code is the "fixed" HAL wherever that's available.
        
         | lulf wrote:
         | You might want to take a look at the embassy project for a
         | unified stm32 HAL. The idea is that it defines the APIs per
         | peripheral version as defined by STM (spi v1, spi v2, usart v1
         | etc). The advantage is that a given peripheral can be used
         | across all stm32 families with that version. This makes
         | maintaining a HAL and keeping a unified API much simpler.
         | 
         | The other part is the stm32-metapac (not specific to async)
         | that generates the PAC for any stm32 chip.
         | 
         | Read more about embassy here: https://github.com/embassy-
         | rs/embassy
        
         | bcantrill wrote:
         | You are going to be very interested in Hubris, our _de novo_
         | Rust operating system for MCUs.[0] We have been doing most of
         | our development on STM32H7s, but Hubris works on both the F3
         | and F4 as well. We 'll be open sourcing it in advance of my
         | colleague Cliff Biffle's presentation at the Open Source
         | Firmware Conference[1]; stay tuned!
         | 
         | [0] https://www.youtube.com/watch?v=XbBzSSvT_P0
         | 
         | [1] https://talks.osfc.io/osfc2021/talk/JTWYEH/
        
           | kennywinker wrote:
           | Anywhere I can look for news about when this launches?
        
             | steveklabnik wrote:
             | The plan is to open source the repository on github roughly
             | at the same time as the talk, so basically, you can set
             | your calendar to that and then go check it out.
        
         | R0b0t1 wrote:
         | > Each HAL implements different things, or the same thing in
         | different ways.
         | 
         | They are generated programmatically from core description files
         | that are only available to STM. They are designed sloppily
         | because a lot of the implementation work is automated. To
         | really progress in this area FOSS developers are going to need
         | to get ahold of these interface specifications.
         | 
         | > Lack of emulation. You can emulate an arm cpu in qemu, but
         | there's no tools for mocking out hardware - which means testing
         | has to happen on device (or you need to fragment your
         | application into qemu-testable pieces).
         | 
         | This should be OK and I almost prefer it. Get a JTAG or SWD
         | adapter, learn how to use GDB and the self test hardware, and
         | you'll be fine. Modern MCUs are designed for test and can be
         | used in circuit just fine. You can control any part of the chip
         | via the trace macrocell.
         | 
         | > Shared memory / global initialization is overly complex.
         | 
         | Related to my first point.
        
           | kennywinker wrote:
           | > This should be OK and I almost prefer it. Get a JTAG or SWD
           | adapter, learn how to use GDB and the self test hardware
           | 
           | I'd really like to write a test that e.g. confirms that if
           | PB13 goes high for longer than 10ms, and event is triggered.
           | Yes, I can run that code on my MCU - but actually testing it
           | requires pressing buttons. With an emulator, I could easily
           | write code to mock out the behavior of external hardware and
           | confirm that my code is handling that input correctly.
           | 
           | > Related to my first point
           | 
           | I'm actually talking about a constraint of Rust - not the HAL
           | or PAC.
           | 
           | Per https://docs.rust-
           | embedded.org/book/concurrency/index.html the canonical way to
           | use a GPIO from an interrupt is something like:
           | static G_LED: Mutex<RefCell<Option<LEDPIN>>> =
           | Mutex::new(RefCell::new(None));              fn main() {
           | // get the gpio and pass off to mutex             let mut led
           | = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
           | // Move the pin into our global storage
           | cortex_m::interrupt::free(|cs| *G_LED.borrow(cs).borrow_mut()
           | = Some(led));         }                   fn interrupt() {
           | static mut LED: Option<LEDPIN> = None;
           | // load the led from the global mutex             let led =
           | LED.get_or_insert_with(|| {
           | cortex_m::interrupt::free(|cs| {                     // Move
           | LED pin here, leaving a None in its place
           | G_LED.borrow(cs).replace(None).unwrap()                 })
           | });             // actually use the led gpio here         }
           | 
           | If we were genuinely using G_LED from main and from the
           | interrupt, the mutex song-and-dance makes sense, since we
           | want to be careful about how we share use of this resource.
           | But since we just want to set it up in main and use it in the
           | interrupt it's a LOT of confusing overhead/abstraction.
        
           | MrBuddyCasino wrote:
           | Do you mean the register-level description generated from
           | SVD? I thought one works mainly with the higher-level HAL
           | traits, or is that not yet possible?
        
             | zwirbl wrote:
             | You would use the traits from embedded-hal to write e.g. a
             | driver for some IC or when implementing functionality in a
             | device agnostic way and then use (or write) a specific HAL
             | driver implementing these
        
               | kennywinker wrote:
               | It's great that embedded-hal exists, but somehow the DMA
               | drivers in the stm32f4xx_hal and stm32f1xx_hal crates
               | have a pretty radically different api, which to me means
               | something's a little broken.
        
           | zwirbl wrote:
           | It's the PACs (peripheral access crates) that are generated
           | from vendor supplied SVD files, including many patches. These
           | are register definitions Most HALs are actually hand written,
           | often leveraging macros to implement similar functionality
           | for multiple peripheral instances
        
           | nereye wrote:
           | Well, with Rust tooling that automates the creation of crates
           | from these 'core description files' (aka CMSIS SVD, System
           | View Description), there is a large interest from other CPU
           | vendors too so SVD seems to have become a de facto standard.
           | For example, Espressif has SVD definitions for their CPUs
           | (e.g. ESP32), which are definitely not ARM:
           | https://github.com/espressif/svd, etc.
        
       | mcraealex16 wrote:
       | Type state programming with embedded Rust has stopped me from a
       | number of bugs so far. The important thing for me is that these
       | bugs were caught at compile time which makes a world of
       | difference in terms of productivity. The biggest pain point is
       | how different the libraries for different microcontrollers are. I
       | feel over time they will converge as things stabilize, time will
       | tell.
        
       ___________________________________________________________________
       (page generated 2021-11-18 23:02 UTC)