Skip to main content
Explorer II
August 9, 2024
Question

USART interrupt handling in Rust

  • August 9, 2024
  • 10 replies
  • 4543 views

Hi, I'm new to embedded (as in one week old) and am trying to build a small system to do a few things for an optical product we're building: mainly temp measurement (Omega SA1-RTD with MAX31865) and LED management for optical lasers. Currently I have both working on STM32F446RE (Nucleo board for now), which is great.

Now, I need to be able to communicate with the system from the computer (Ubuntu box). We have the rest of the system (a collection of 10 motors, all daisy chained to work with MODBUS over RS485) connected to the computer via an RS485/USB adapter. I was thinking of making this STM32 system act as another peripheral to be part of that daisy chain.

My question now is: how can I build this communication link? I have a working example of interrupt handling with the user button on the Nucleo on EXTI15_10. However, I'm not sure how I can set up interrupts for USART (I'm assuming that'd be the way for MODBUS). I hooked up for USART2, but don't see how I can receive the MODBUS messages via interrupts. In general, what is the process for interrupt handling? E.g., where is the info on which kind of event (like the serial event) generates what kind of interrupt (like the EXTI15_10 above)?

I'm building this in Rust, so unfortunately the C/C++ code examples online aren't super helpful, but even if you don't have pointers on Rust code, if you could just explain the theory or point to references, I'd really appreciate it. I do have Electronics background. Thanks a bunch!

    This topic has been closed for replies.

    10 replies

    Super User
    August 9, 2024

    Peripherals like UART have their own interrupts besides EXTI. See the reference manual RM0390 USART chapter for details at the register level. Set the RXNEIE (receive register not em,pty interrupt enable) bit in the CR1 register and implement an interrupt handler. You also have to enable the interrupt in NVIC and, for reliable communication, implement error handling. 

    For higher baud rates/less CPU load, UART is often combined with DMA: MaJerle/stm32-usart-uart-dma-rx-tx: STM32 examples for USART using DMA for efficient RX and TX transmission (github.com).

    Not idea how this all translates to Rust :).

    Looking from the other side, there are MODBUS libraries like https://github.com/alejoseb/Modbus-STM32-HAL-FreeRTOS.git 

    hth

    KnarfB

    sekharAuthor
    Explorer II
    August 9, 2024

    Thank you for the prompt response. I was connecting for USART via PA2/PA3, but I now see from the doc that USART is via ST-Link by default. I tried sending via the USB, and yes the interrupts triggered. I need to look at the DMA option you mentioned next. Much appreciated!

    Super User
    August 9, 2024

     I'm new to embedded (as in one week old) 

    Consider for this mini-project on STM32 to descend to plain C or C++ from the rusty heights. You will lose only a week, but will save much more time end effort. Because most of available examples are in C/C++. 

    Super User
    August 9, 2024

    @Pavel A. wrote:

    Consider for this mini-project on STM32 to descend to plain C or C++ from the rusty heights.


    +1 to this :thumbs_up:

    @sekhar  Get a C example working. Then you can take that as the specification of what your Rust code needs to do...

    sekharAuthor
    Explorer II
    August 9, 2024

    Thank you @Pavel A. and @Andrew Neil, yes that is good and very practical advice. But doing it in Rust isn't as hard as it might sound though, even with lack of examples. Look at it this way. I started with all this on Monday, as in: I knew nothing at all about using microcontrollers, let alone STM32, actually no experience with HW of any kind (all my work has been in software). By Tuesday I had the dev setup (VSCode with debugging) worked out and a blinking LED; and by Wednesday, temperature access of an RT100 device with another board (MAX31865) in the mix. This is not to brag, but to say that if I can do it, so can others; and it can be quick to get started with microcontrollers (certainly SMT32) using Rust.

    I do agree though there are a ton of examples on C/C++, but I'm not sure starting from them is ideal if your goal is to do in Rust based on the examples I found (I did try that BTW, trying to go from C++ examples to Rust). For starters, it appears to me (I'm new, so may be wrong here), the way you approach coding for STM32 and organize your code is very different, so the logic doesn't seem to translate.

    Also, on day one (Monday) I did try to use STM32CubeIDE, not to do it in C++ but to just look at the board I connected via the USB (which I didn't know how to access). And I immediately ran into a bunch of issues. The deb version would not work on Ubuntu box. Searching online led me to installing the generic Linux version, but I couldn't do anything useful with it either because it ran into other issues like no libncurses.so.5 (I have libncurses.so.6 and there is no option anymore that I see to get this outdated version). Rash of issues like this. Not to mention that this is based on Eclipse, which IMO is dated compared to newer ones like VSCode.

    Anyway, all this is from a newbie viewpoint, please take it from what it's worth. I'm only writing to encourage other folks looking to do it in Rust. Bottom line though, the USART interrupts worked immediately when I accessed via ST-Link (I was connecting through the on-board pins, which apparently are not set by default for USART). I'm sure I'll run into other issues, but at least this hurdle is crossed.

    This community is great BTW, and you're so welcoming of newbies like me.

    Super User
    August 9, 2024

    Of course it depends on your actual goal. I've guessed that the goal is getting working solution, as fast as possible, with minimal bruises, but it was a wrong guess ))

     

    sekharAuthor
    Explorer II
    August 9, 2024

    No, you were absolutely correct: the #1 priority right now is speed, which is why I'm scrambling. We're planning for user tests on 8/22, which gives me only one more week to not only have everything running but also have it installed in the machine and tested, which is crazy. But as I explained above, for me it is turning out to be slower to build in C++ and perhaps not even feasible: trying the IDE was one of the first things I tried on Monday to save time but I couldn't get the darned STM32CubeIDE to work on Ubuntu because of the issues. Are you guys not working on Ubuntu? May be I'm missing something.

    Super User
    August 9, 2024

    If you ask me - my primary working system is Windows, exactly because everything Just Works on it. We use Ubuntu, Fedora, Debian, OS/X and anything needed for the customer. But to save our time, work-life balance and nerve cells - only Windows for the tools. Of course, with wsl, Docker Desktop, gitlab and all that stuff as needed. Not free - so what? I'm grown up and can pay for my tools and toys.

     

    ST Employee
    August 12, 2024

    Hello 

    Just curious: what Rust framework are you using for STM32F4 Peripheral Access Crate / HAL ?

    stm32-rs ?

    Embassy ?

    Guillaume

    sekharAuthor
    Explorer II
    August 14, 2024

    @Guillaume KI'm just using stm32f4xx-hal with the stm32f446re I have on the Nucleo 64 board, which is working for the two things I wanted: laser LED control and temp monitoring (via max31865). I also got the Nucleo 144 (stm32f429) and Bluepill (stm32f103) that I'm experimenting with. I'm planning to check out embassy though in the near future but don't have a need for it right now.

    ST Employee
    August 12, 2024

    How do you connect the STM32F446 USART2 to the rest of the RS485 link ?

    Are you using a TTL-to-RS485 adapter like MAX485 ?

    ST Employee
    August 14, 2024

    Hi @sekhar 

    Here are some info I found about using modbus/RS485 on STM32 (with Rust and C):

    The STM32s don't have RS485 interface. You can use USART with an external adapter.

    example in Rust using MAX485 and STM32F103:

    https://github.com/alttch/stm32f1-modbus-example

    The stm32f4xx-hal has an example in Rust of USART with DMA (and interrupts) :
    https://github.com/stm32-rs/stm32f4xx-hal/blob/master/examples/uart-dma.rs

    we can see use of #[interrupt] to declare interrupt vector
    #[interrupt]
    fn USART3() {
    }

    the interrupt vectors like USART3 are declared in the stm32f4 peripheral access crate . it must be included in your project. If you use stm32f4xx-hal, it uses stm32f4 PAC.

    also:

    cortex_m::interrupt::free(|cs| { /* some code in critical section */}
    this function ensure the closure is running free of interrupts.


    I found some posts about using modbus/RS485 on STM32 (using C code):


    https://community.st.com/t5/stm32-mcus-products/modbus-over-rs485-with-stm32f303k8/td-p/165261
    https://community.st.com/t5/stm32-mcus-products/modbus-with-rs-485-communication/td-p/228333
    https://community.st.com/t5/stm32cubemx-mcus/stm32g484-rs-485-and-modbus-how-to-configure-in-cubemx/td-p/176276

    Note that there are some STM32 series that have basic "support" of modbus .
    it is limited. on USART. only few feature in HW: detection of end of transmission (end of word).
    the user has to implement a lot in software.
    the STM32F446 doesn't have this. other series have it. STM32F303 for example. but also the H7.

    Still, on STM32F446 It may be possible to do same function in software (detection of end of modbus command).

     

    for a modbus crate in Rust you can have a look at:

    https://crates.io/crates/rmodbus

     

    sekharAuthor
    Explorer II
    August 17, 2024

    Thank you @Guillaume K, I'll check these out, much appreciated.

    ST Employee
    August 19, 2024

    If you are happy with my answer, please click on Accept as Solution.