Blink An LED On A PIC32 With Rust, Easily

Got a PIC32 microcontroller and a healthy curiousity about the Rust programming language and its low-level capabilities, but unsure how to squash the two of them together with a minimum of hassle? If that’s the case, then today is your lucky day!

[Harry Gill] has you covered with his primer on programming a PIC32 with Rust, which will have you blinking an LED in no time. [Harry] admits that when he got started, his microcontroller programming skills were a bit rusty, so don’t let yourself think setting this up is beyond your abilities. If you have a working knowledge of the basics of microcontroller programming, you’ll be fine. [Harry] had to jump through a few hoops to get the right tools working, but thoughtfully documented the necessary steps, and provides a bare minimum hardware list.

Unsure what Rust is or what it offers? Check out the basics here, and see if it’s something that interests you. If you want to look even deeper, check out the kind of work that goes into writing a bare metal kernel in Rust.

25 thoughts on “Blink An LED On A PIC32 With Rust, Easily

  1. The obvious question. Can it blink as fast as C?

    #################
    That is a JOKE BTW.
    #################

    One would hope it can produce code of similar quality and so I hope the comments don’t turn into another my language is faster than yours war! That would be SO boring)

    Why Rust ?
    C and by extension C++ are great languages and rule the roost as far as microcontrollers are concerned, but yeah, they do have a lot of problems which can trip you up without spending an inordinate amount of time learning about them.
    Incidentally some complain, “how could they ever have designed a language this way?” Well I think they did pretty well working from pretty much a blank sheet. And in hindsight C and C++ taught us an awful lot about what works in language design for a bare metal language. So yeah Rust…

    The main issue Rust has for someone like me is inertia, so in my case for example I have 30 years of C++ clogging up my brain, but if you are younger and Rust can compete with C for code performance and catch more bugs then Rust is surely worth looking into.

    1. I agree, that there is a lot to learn from C/C++ and I understand your reasons to stick with them, but there is a lot to learn from Rust as well. I recently started programming Rust (after 10 years of C/C++) and learned that the memory management patterns enforced by the Rust compiler can be very benificial in other languages too. I can only recommend having a look at Rust, even if you don’t want to use it productively!

    2. On my limited tests, the generated machine code was just as good as from modular C/C++ code.

      With one exception, when sharing a resource like an GPIO pin or SPI bus, you quickly run into the need of a RefCell, which has extra runtime overhead. While in C/C++ you’ll most likely share a pointer.

    3. I’m a long-time C guy. Embedded developer, RTOS author, and Linux kernel hacker. I think I understand C’s dominance. First it is ubiquitous in the industry, when a vendor supplies tools it’s almost always an assembler, debugger, and C compiler. Second is availability for new platforms, the first open source to support a new SoC or architecture is usually gcc and llvm, And third, there is a fair amount of community knowledge that is shared in the lingua franca of C.

      All that said, I think Rust has a potential to displace C and C++ in system software, kernel development, and embedded development. The inertia is a factor, I might be retired by the time C loses its top dog status in the embedded world. But if history is any guide these changes are inevitable.

      Big changes in the embedded world are likely to lead people to find something more expressive than C. It might be multi-threaded and parallel programming, it might be some of the deep learning and DNN development where C feels a bit clunky. It might be more data collection and processing needed by edge computing, and the improvements in memory management and data structures that Rust offers over C.

      As for learning a new language. I think I’m best at C. But I know a bunch of them over the years. I think only ones I get to use professionally and with any frequency are Go, shell script, JavaScript, and Java. (does TeX count as programming?). I think once you know C and something substantially different like Lisp or ML, then concepts in Rust, Scala, Haskell, etc are not too hard to grasp.

      The big thing I lose when I step away from old familiar C is my ability to spot common bugs at a glance.

    1. Well….

      In this case that isn’t actually so.

      When trying out a new microcontroller or toolchain or even indeed pcb or dev board, blinking an led is generally a good choice of first application to get working.

      The successful LED blink shows your pcb, programming hardware and upload commands are working and also shows you got the timing right , or not.

      And seeing that LED blinking is usually a moment to celebrate (and /or breathe a sigh of relief)

      Once that LED is working it can then be used for basic debugging, while you get some higher level comms up and running…

        1. And those who are here [1] for a longer time, do know that it is good to welcome a new generation.

          So enjoy the rerun that is not a rerun for every one.

          [1] Hackaday and/or Earth

  2. Had you worked on automotive projects you would’ve known that C is here to stay for another 20-50 years (pretty much like B-52 bombers). A major car company needs a new part – so they specify requirements, functionality and so on… all the stuff that automotive parts provider company will need to stick to. For at least 30 years they had their tried and tested process for procuring and evaluating any new electronic parts. A part of their requirements consist of a report on MISRA compliance, code coverage by static analysis and tests. They don’t give a toss about that new fancy programming language because that would mean discarding existing tools and more importantly processes. It’s not only about programming geeks toying around with new language and its compiler, it’s also a matter of all those Karens who get to fill absurd amounts of Excel spreadsheets just to comply with the holy “software development process”. It may all be incredibly flawed but no one, from the software engineers at the very bottom to top management doesn’t want to be responsible for costs of change and also possible liability if something goes wrong with the new stuff, even if it’s much better.

    … and then there are also turds like AUTOSAR… yeah.

    It’s good that people experiment with new possibilities but it’s the giants who gobble up most of the available microcontrollers on the market that get to dictate what’s considered a standard.

  3. I never stop being confused by:

    pps.rpb0r.write(|w| unsafe { w.rpb0r().bits(0b0010) }); // U2TX on RPB0

    I somewhat understand the construct now, but I still cannot understand how someone can bother to write that on a regular basis. I guess that is the reason why every bit has to be wrapped in an autogenerated function now, even though it gets rid of all the efficiency benefits that the weird construct is supposed to achieve.

  4. I don’t think it’s worse than the equivalent in C:

    PPS_RBP0R &= ~(PPS_RBP0R_RPB0R_MASK << PPS_RBP0R_RPB0R_SHIFT);
    PPS_RBP0R |= 0x02 << PPS_RBP0R_RPB0R_SHIFT;

    And at least Rust has tab completion in most editors, which will work well here because the type of 'w' is known. Add it will error out at compile time if you try to set a field that doesn't exist in that register. C won't care what you shift or mask, or where you do it.

    And there's docs.rs – although I accept the auto-generated docs on that particular kind of auto-generated code could be improved.

    And the auto-generated functions don't really impact efficiency because they all get optimised away. Even the closure (aka lambda function).

  5. It’s petty funny when people say that they program in C because they say they can find the bugs easier when there is very substantial evidence from bug reporting statistics that says that C programmers are really really terrible at spotting bugs. Just look at apache httpd, written by the world’s best C programmers, absolutely laden with bad bugs. Apache project management wants desperately to rewrite it in Rust before there are any more disasters.

  6. Another fascinating thing about C: if you take some random C program and compile it with gcc, clang, Solaris C, Microsoft C, and AIX C, you will get five completely different sets of warning messages. So really you need to be compiling with all five if you actually want to catch all your bugs.

    1. I looked briefly into using LLVM with PIC16cXX series when LLVM was young as I was fed up writing in MPASM, but LLVM assembler is quite restrictive so say you want for example to multiply i8 * i8 -> i16. then you have to convert each i8 to i16 and then do i16 * i16 -> i16.
      https://llvm.org/docs/LangRef.html#mul-instruction.
      But PIC16cXX has no hardware multiplier so this will take maybe 4x as long as if you used your own MPASM macro.
      Coupled with PIC16 having Harvard achitecture with 12/14 bit code bus IIRC and 8 bit data bus,a hardware stack and very little RAM meant the memory model just isn’t a great fit for C ( so the Microchip C compiler takes a lot of liberties with C language, so many ANSI C libraries won’t “just work”)

      There was once a PIC16 backend for LLVM but apparently it was dropped:
      https://groups.google.com/g/llvm-dev/c/sng74KXRU4o

      AVR micro hardware on the other hand( maybe based on PIC16 experience) was designed from ground up to be a good fit for C, hence its success in Arduino etc and there is an (unloved experimental) LLVM backend for AVR.

      Meanwhile good old gcc has a Rust backend apparently. https://github.com/Rust-GCC

  7. I’m going to go really old-school here; I don’t understand why everyone loves high level languages like C, rust, and (shudder) C++ so much for embedded stuff when the macro assemblers and supporting tooling for these platforms is so awesome.

    I did a lot of hard real-time on PIC16 back in the day and the precision timing you could get from instruction counting (every instruction is 4 clock cycles except branches are 8) was a luxury you can’t get in high level languages or even other CPUs. The Harvard architecture and tiny ram with no stack made it a really poor fit for C, but it was perfect for macro- assembler and the applications it was intended for. It was ideal for real-time and/or state machines.

    Provided you are systematic and disciplined, macro assembler is not that different from normal procedural languages. The same design, unit test, integration test, etc processes apply, and you quickly collect/build libraries of useful macros. Throw in the awesome simulation and debug tooling PIC provides and the whole experience was great fun. I don’t understand why you’d want to ruin it by trying to add C or Rust to the mix.

Leave a Reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.