Author Topic: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)  (Read 35115 times)

0 Members and 1 Guest are viewing this topic.

Online tggzzz

  • Super Contributor
  • ***
  • Posts: 19791
  • Country: gb
  • Numbers, not adjectives
    • Having fun doing more, with less
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #275 on: March 24, 2023, 12:59:56 pm »
IMO Abstraction means Least Common Denominator,

I've seen many international standards where the abstraction is the highest common multiple. That enables all manufacturer's equipment to conform to the standard. (Or at least the parts of the standard that they have implemented, cough).

That can still have advantages for clients of the various manufacturers' equipment, but it still allows manufacturer lockin.
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline coppice

  • Super Contributor
  • ***
  • Posts: 8783
  • Country: gb
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #276 on: March 24, 2023, 01:07:16 pm »
IMO Abstraction means Least Common Denominator, and as such is perpendicular to everything Controller in microControllers. In other words, if you want to use microcontrollers with Rust, you must learn how to write those pesky hardware-related libraries crates. Or just do the Arduino thing - there's nothing wrong with that, the world is not black and white.
There is a weird trend in MCUs. People have unique features in their peripherals that put them head and shoulders above the competition for specific applications, but in 2023 all they want to do is dumb things down by pushing abstraction libraries that only expose the most basic generic features. For an MCU, abstraction is great for things like ethernet and USB interfaces. It loses most of the interesting qualities of most other peripherals.
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 27190
  • Country: nl
    • NCT Developments
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #277 on: March 24, 2023, 01:43:15 pm »
IMO Abstraction means Least Common Denominator, and as such is perpendicular to everything Controller in microControllers. In other words, if you want to use microcontrollers with Rust, you must learn how to write those pesky hardware-related libraries crates. Or just do the Arduino thing - there's nothing wrong with that, the world is not black and white.
There is a weird trend in MCUs. People have unique features in their peripherals that put them head and shoulders above the competition for specific applications, but in 2023 all they want to do is dumb things down by pushing abstraction libraries that only expose the most basic generic features. For an MCU, abstraction is great for things like ethernet and USB interfaces. It loses most of the interesting qualities of most other peripherals.
I depends a bit on how the HAL is implemented. Recently I have been working on some STM32 projects and I find ST's HAL absolutely horrific and inconsistent. Where I can, I am replacing the HAL parts with bare metal code that just works better and is easier to use.

OTOH I find the way Linux deals with low level interfaces much better while it doesn't incur much overhead. You have open, read, write, close and ioctl that work on what is basically a file on the file system. Only ioctl deals with peripheral specific stuff. You can implement something similar for a microcontroller with a much thinner interface.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3159
  • Country: ca
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #278 on: March 24, 2023, 02:58:04 pm »
Another difference is that the Rust code refuses to compile when I do it wrong. I am still stuck mind you. But not with a program that compiles and crashes for reasons I do not understand.

What's wrong with understanding reasons? It's not a rocket science you know. You did well with recvmsg() in the end. A few dozens of such cases and seeing reasons won't be that hard any more.
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8240
  • Country: fi
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #279 on: March 24, 2023, 03:54:16 pm »
What's wrong with understanding reasons? It's not a rocket science you know. You did well with recvmsg() in the end. A few dozens of such cases and seeing reasons won't be that hard any more.

Learning from mistakes is not just how to avoid those exact mistakes by learning higher level of self-control, but how to improve things so that whole classes of mistakes just disappear. This mindset has been highly successful in aviation safety, for example.

That being said, one needs to be careful so they understand the root causes properly, to do the right decisions. One should also look at the aviation safety here. No recommendations are made until the root causes and significant contributing factors are well understood.

Some of the weirdest POSIX interfaces need good usability wrappers, or at very least good documentation with examples covering most usual use cases. It's a pity they are not widely/commonly available.
 

Offline coppice

  • Super Contributor
  • ***
  • Posts: 8783
  • Country: gb
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #280 on: March 24, 2023, 05:18:49 pm »
Some of the weirdest POSIX interfaces need good usability wrappers, or at very least good documentation with examples covering most usual use cases. It's a pity they are not widely/commonly available.
Where POSIX differs from straight up traditional Unix its supposed to be to overcome shortcomings that experience has shown in the original. However, in many cases they just seem to have achieved an even quirkier API.
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 27190
  • Country: nl
    • NCT Developments
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #281 on: March 24, 2023, 05:27:19 pm »
Some of the weirdest POSIX interfaces need good usability wrappers, or at very least good documentation with examples covering most usual use cases. It's a pity they are not widely/commonly available.
Where POSIX differs from straight up traditional Unix its supposed to be to overcome shortcomings that experience has shown in the original. However, in many cases they just seem to have achieved an even quirkier API.
On systems with an OS you are way better of using at least C++ and one of the many frameworks (like Boost, Qt, Wxwidgets, etc) to turn the OS calls into sensible interfaces.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3159
  • Country: ca
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #282 on: March 24, 2023, 05:29:26 pm »
What's wrong with understanding reasons? It's not a rocket science you know. You did well with recvmsg() in the end. A few dozens of such cases and seeing reasons won't be that hard any more.

Learning from mistakes is not just how to avoid those exact mistakes by learning higher level of self-control, but how to improve things so that whole classes of mistakes just disappear. This mindset has been highly successful in aviation safety, for example.

Before you can improve on something you need to understand what is the root cause.

Whether you use your own means or external tools to solve a problem, the understanding is a must. Without understanding, everything would look like a magic to you - a la "my program crashes, I need a better language which will fix this", or "I changed an unrelated line of code and look - my bug is fixed and MCU doesn't crash any more".

 
The following users thanked this post: Siwastaja, SiliconWizard

Offline uliano

  • Regular Contributor
  • *
  • Posts: 176
  • Country: it
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #283 on: March 25, 2023, 08:25:21 pm »
I had some time to spend and finally I'm starting to grok a little.


Even if  community seems more concerned with the high level abstraction HAL I'll probably dig into the lower layer PAC before. I'm always afraid of thing done by opaque layer of software, brings my mind to Arduino...


I was SO WRONG!

To the point that I could go further the silly examples only after discovering rtic.rs which sits above the HAL

A software task (driven through the unused SPI1 interrupt by systick) every 10ms generates a pulse on PB1 which is electrically connected to PB0 where an higher priority, EXTI0 driven, task generates a pulse on PB2 while the led is blinking at 1Hz and log messages are sent through RTT in about 100 lines of code. It is not even Rust, rather a kind of application specific language implemented in macro but, once in the known, the code is rather clear and even elegant.

Also I gave up to generic tools such as cortex-debug, openOCD, gdb... and adopted the native probe-rs (with its VSCode extension), cargo-flash cargo-embed...

Finally, I was rather skeptical about the thaumaturgical powers of static analysis but I should say that the design contracts implemented by the HAL are quite effective in preventing lots of silly distraction mistakes. In my short (one day) experience I can say that once it compiles it runs, maybe it does not do what it was meant for, but it doesn't hang or crash, to the point that I never felt the need to reach for the debugger.

Next step will be to try some simple peripherals like I2C or SPI.


Code: [Select]
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]

use panic_rtt_target as _;
use rtic::app;
use rtt_target::{rprintln, rtt_init_print};
use systick_monotonic::{fugit::Duration, Systick};
use systick_monotonic::fugit::Instant as Instant;

#[app(device = stm32f4xx_hal::pac, peripherals = true, dispatchers = [SPI1])]
mod app {
    use super::*;
    use stm32f4xx_hal::{
        gpio::{Input, Output, PushPull, Edge, PC13, PB0, PB1, PB2},
        prelude::*
    };
    // use stm32f4xx_hal::prelude::*;

    #[shared]
    struct Shared {}

    #[local]
    struct Local {
        input:  PB0<Input>,
        signal: PB1<Output<PushPull>>,
        output: PB2<Output<PushPull>>,
        led: PC13<Output<PushPull>>,
        count: u32,
        start_time: Instant<u64, 1, 1000>
    }

    #[monotonic(binds = SysTick, default = true)]
    type MonoTimer = Systick<1000>;

    #[init]
    fn init(mut cx: init::Context) -> (Shared, Local, init::Monotonics) {
        rtt_init_print!();
        rprintln!("init");

        // Setup clocks
        let rcc = cx.device.RCC.constrain();
        let mono = Systick::new(cx.core.SYST, 96_000_000);
        let _clocks = rcc
            .cfgr
            .use_hse(25.MHz())
            .sysclk(96.MHz())
            .hclk(96.MHz())
            .pclk1(48.MHz())
            .pclk2(96.MHz())
            .freeze();

        // Setup Pins
        let gpioc = cx.device.GPIOC.split();
        let mut led = gpioc
            .pc13
            .into_push_pull_output();
        led.set_high();
        let mut syscfg = cx.device.SYSCFG.constrain();
        let gpiob = cx.device.GPIOB.split();
        let mut input = gpiob
            .pb0
            .into_pull_down_input();
        input.make_interrupt_source(&mut syscfg);
        input.trigger_on_edge(&mut cx.device.EXTI, Edge::Rising);
        input.enable_interrupt(&mut cx.device.EXTI);
        let mut signal = gpiob
            .pb1
            .into_push_pull_output();
        signal.set_low();
        let mut output = gpiob
            .pb2
            .into_push_pull_output();
        output.set_low();

        // Schedule the blinking task 10 ticks = 10 ms from now
        let first_time = monotonics::MonoTimer::now() + Duration::<u64, 1, 1000>::from_ticks(10);
        blink::spawn_at(first_time).unwrap();

        (
            Shared {},
            Local { input, signal, output, led, count: 0, start_time: first_time },
            init::Monotonics(mono),
        )
    }

    #[task(local = [led, signal, count, start_time], priority = 1)]
    fn blink(cx: blink::Context) {
        cx.local.signal.set_high();
        cx.local.signal.set_low();       
        if *cx.local.count == 100 {
            cx.local.led.set_high();
            rprintln!("blink");
        }
        if *cx.local.count == 200 {
            cx.local.led.set_low();
            *cx.local.count = 0;
            rprintln!("blonk");
        }
        *cx.local.count += 1;
        // Schedule the next blinking task 10 ticks later
        *cx.local.start_time += Duration::<u64, 1, 1000>::from_ticks(10);
        blink::spawn_at(*cx.local.start_time).unwrap();
    }

    #[task(binds = EXTI0, local = [input, output], priority = 2)]
    fn on_exti0(cx: on_exti0::Context){
        cx.local.output.set_high();
        cx.local.output.set_low();
        cx.local.input.clear_interrupt_pending_bit();
    }
}


« Last Edit: March 25, 2023, 08:28:36 pm by uliano »
 
The following users thanked this post: nctnico

Online tggzzz

  • Super Contributor
  • ***
  • Posts: 19791
  • Country: gb
  • Numbers, not adjectives
    • Having fun doing more, with less
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #284 on: March 25, 2023, 09:14:01 pm »
I had some time to spend and finally I'm starting to grok a little.
...
I was SO WRONG!
...
Finally, I was rather skeptical about the thaumaturgical powers of static analysis but I should say that the design contracts implemented by the HAL are quite effective in preventing lots of silly distraction mistakes. In my short (one day) experience I can say that once it compiles it runs, maybe it does not do what it was meant for, but it doesn't hang or crash, to the point that I never felt the need to reach for the debugger.

Thank you for those comments.

It is always a pleasant surprise to find someone that looks, thinks, tries, understands the subtleties, and even changes their mind. That is all too rare - and useful for other people :)
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14648
  • Country: fr
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #285 on: March 25, 2023, 11:41:28 pm »
I dig this kind of stuff:
Code: [Select]
blink::spawn_at(*cx.local.start_time).unwrap(); ;D
 

Offline coppice

  • Super Contributor
  • ***
  • Posts: 8783
  • Country: gb
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #286 on: March 26, 2023, 02:34:15 pm »
no, no, no! this thread is only meant for philosophical discussions about whether Rust should exist, untethered to any real-world experience with it! not stories about how using it was productive and educational for you!  :rant:
In a universe with abundant oxygen the existence of rust is beyond question. It will always be with us. As the great philosopher Neil Young noted - Rust Never Sleeps.
 
The following users thanked this post: SiliconWizard, karpouzi9

Offline uliano

  • Regular Contributor
  • *
  • Posts: 176
  • Country: it
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #287 on: March 26, 2023, 04:05:19 pm »
sorry, my bad!

I will amend myself by showing this grotesque type annotation (and yes I needed to write this)

Code: [Select]
        lcd: Ili9341<SPIInterface<Spi<pac::SPI1, (Pin<'A', 5>, NoPin, Pin<'A', 7, Alternate<5>>), false>, Pin<'A', 4, Output>, Pin<'A', 2, Output>>, Pin<'A', 3, Output>>
 
The following users thanked this post: SiliconWizard

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3159
  • Country: ca
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #288 on: March 26, 2023, 04:07:06 pm »
no, no, no! this thread is only meant for philosophical discussions about whether Rust should exist, untethered to any real-world experience with it! not stories about how using it was productive and educational for you!  :rant:

Too late. I have already noticed it. 113 lines for LED blinker - that's really amazing productivity. And the warm feeling that your LED blinker will never crash. Priceless.
 
The following users thanked this post: SiliconWizard

Offline ve7xen

  • Super Contributor
  • ***
  • Posts: 1194
  • Country: ca
    • VE7XEN Blog
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #289 on: March 27, 2023, 07:52:49 am »
Too late. I have already noticed it. 113 lines for LED blinker - that's really amazing productivity. And the warm feeling that your LED blinker will never crash. Priceless.
:palm:

A minimal LED blinker for stm32f103 using embedded_hal is 30 lines, it's all the same initialization stuff you need to do with C...

Code: [Select]
#![no_std]
#![no_main]

use cortex_m_rt::entry;
use nb::block;
use panic_halt as _;
use stm32f1xx_hal::{pac, prelude::*, timer::Timer};

#[entry]
fn main() -> ! {
    let cp = cortex_m::Peripherals::take().unwrap();
    let dp = pac::Peripherals::take().unwrap();

    let mut flash = dp.FLASH.constrain();
    let rcc = dp.RCC.constrain();

    let clocks = rcc.cfgr.freeze(&mut flash.acr);

    let mut gpioc = dp.GPIOC.split();

    let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
    let mut timer = Timer::syst(cp.SYST, &clocks).counter_hz();

    timer.start(2.Hz()).unwrap();

    loop {
        led.toggle();
        block!(timer.wait()).unwrap();
    }
}

Quote
I will amend myself by showing this grotesque type annotation (and yes I needed to write this)

You can usually avoid this mess in function signatures by using traits instead, but it can be unavoidable in your shared state, but really should only exist in one place. This is a wart for sure, but the complex strong types are also the strength. I suspect as embedded Rust matures, there will be some 'standard' macros that emerge to make dealing with this a bit more ergonomic.

async in no-std is pretty exciting for embedded, IMO. Still pretty experimental, but Embassy looks fairly mature.
« Last Edit: March 27, 2023, 07:58:09 am by ve7xen »
73 de VE7XEN
He/Him
 
The following users thanked this post: nctnico, wek

Offline uliano

  • Regular Contributor
  • *
  • Posts: 176
  • Country: it
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #290 on: March 27, 2023, 10:18:02 am »


A minimal LED blinker for stm32f103 using embedded_hal is 30 lines, it's all the same initialization stuff you need to do with C...

yeah, in effect it was advertised as
Quote
A software task (driven through the unused SPI1 interrupt by systick) every 10ms generates a pulse on PB1 which is electrically connected to PB0 where an higher priority, EXTI0 driven, task generates a pulse on PB2 while the led is blinking at 1Hz and log messages are sent through RTT

maybe someone can't or won't read...

Quote

You can usually avoid this mess in function signatures by using traits instead, but it can be unavoidable in your shared state, but really should only exist in one place. This is a wart for sure, but the complex strong types are also the strength.

I wasn't really complaining, rather sticking to the "social protocol" for this thread.  :-//
Quote
I suspect as embedded Rust matures, there will be some 'standard' macros that emerge to make dealing with this a bit more ergonomic.

async in no-std is pretty exciting for embedded, IMO. Still pretty experimental, but Embassy looks fairly mature.

My plan is to stick with rtic, at least initially, I feel much more at home having to deal with interrupt tasks, also my Rust proficiency is, at the moment, quite low and it's probably better to await alittle till it grows to an acceptable state.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3159
  • Country: ca
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #291 on: March 27, 2023, 05:44:28 pm »
A minimal LED blinker for stm32f103 using embedded_hal is 30 lines, it's all the same initialization stuff you need to do with C...

Same stuff ... Who would've thought.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14648
  • Country: fr
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #292 on: March 27, 2023, 06:34:13 pm »
This is cute.
 

Offline wek

  • Frequent Contributor
  • **
  • Posts: 498
  • Country: sk
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #293 on: March 27, 2023, 08:19:11 pm »
Hi ve7xen,

A minimal LED blinker for stm32f103


Thanks for the example.

Could you please perhaps comment it, explaining what element does what in that example, for us, uninitiated?

Thanks,

JW
 

Offline ve7xen

  • Super Contributor
  • ***
  • Posts: 1194
  • Country: ca
    • VE7XEN Blog
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #294 on: March 27, 2023, 09:17:31 pm »
Thanks for the example.

Could you please perhaps comment it, explaining what element does what in that example, for us, uninitiated?

Thanks,

JW

Sure. Keep in mind I'm by no means a Rust expert (though I have spent some time with it making small CLI tools and web APIs), and have only spent some hours here and there tinkering with embedded rust over the last couple years.

A 'crate' is sort of a source library. It can include runtime code, compile time macros, and so on. Using them is integrated into the cargo build tool that is the normal way to build anything with Rust.

Code: [Select]
// Tell the tools not to build or link to the Rust standard library. std requires a heap allocator, which you can bring in if you want (for example from the embedded-alloc crate)
#![no_std]
// Likewise, we don't want any of the normal setup code for a hosted binary, so don't set up an entry point
#![no_main]

// `use` instructs the compiler to import modules from external crates
// This is the setup code (interrupt vectors, static init etc.) for cortex m, and will create our entry point. This crate also contains similar macros for ISRs.
use cortex_m_rt::entry;
// A macro to busy wait on a predicate
use nb::block;
// A panic handler is required.
// 'panic_halt' just halts the CPU. Other options might be `panic_semihosting` to print the panic message to the semihosting environment, or your own implementation.
// We just need to import it into the build, we won't reference it anywhere, so it imports as _ which in Rust usually means 'I don't need this'
use panic_halt as _;
// Here we bring in the device support module.
//  pac is the 'peripheral access crate', basically register maps
//  prelude in rust modules is usually a convenience module that lets you import 'all the typically useful stuff' in one use statement
//  timer::Timer lets us use a timer peripheral to create the delay we need
use stm32f1xx_hal::{pac, prelude::*, timer::Timer};

// This is the cortex_m_rt::entry macro and flags the function as the entry point
#[entry]
// Function signature, -> sets the return type, ! means 'returns nothing', which is distinct from returning None
fn main() -> ! {
    // Generally there are 'core peripherals' from a processor support crate, and 'device peripherals' from a device support crate.
    // In this case we need the core peripherals for the SysTick timer, and device peripherals for RCC, GPIO and Flash controllers
    // So we reference the module and 'take()' to transfer ownership to our context, as these are singletons.
    // This operation can fail (if for example they are already owned), so returns a Result that can be an error or contain a value
    // we unwrap() it to get the inner value, and panic if it's an error instead.
    let cp = cortex_m::Peripherals::take().unwrap();
    let dp = pac::Peripherals::take().unwrap();

    // Our specific device has 'specialized' peripherals from the PAC, but we need them as standard HAL objects to use the traits from HAL
    // so we take the device peripheral and 'constrain' it to the HAL specification, which gives us an owned HAL-type object
    let mut flash = dp.FLASH.constrain();
    let rcc = dp.RCC.constrain();

    // We will need a Clocks object later to set up the timer. This describes the clock configuration in the system. To get it,
    // we must 'freeze' the clock configuration register. This 'consumes' the reference to the register and makes the borrow
    // checker guarantee for us that we can't reference it anywhere else. In other words, it guarantees that as long as the Clocks
    // object we create here exists, it will reflect the running clock configuration. Trying to reference rcc.cfgr after this will result in a compile error.
    let clocks = rcc.cfgr.freeze(&mut flash.acr);

    // split() is similar to constrain() above and basically lets us take ownership of a reference to a standard HAL representation of a peripheral
    let mut gpioc = dp.GPIOC.split();

    // Configure the pin and take ownership of it (we borrow crh mutably from the port to make the change)
    let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
    // Here we take cp.SYST (reference to the SysTick timer) and create a usable timer with 1Hz resolution from it, based on the clock setup we fixed earlier
    let mut timer = Timer::syst(cp.SYST, &clocks).counter_hz();

    // Start the timer with a 2Hz period. Consuming Results is mandatory in Rust, so we have to unwrap() here.
    timer.start(2.Hz()).unwrap();

    loop {
        led.toggle();
        // our predicate here is timer.wait() which returns an Err until the timer fires, when it will return an Ok, which unblocks the block macro
        block!(timer.wait()).unwrap();
    }
}
[code]
73 de VE7XEN
He/Him
 
The following users thanked this post: wek

Offline wek

  • Frequent Contributor
  • **
  • Posts: 498
  • Country: sk
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #295 on: March 27, 2023, 09:39:15 pm »
Thanks. This will take some time to digest... :-)

JW
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3159
  • Country: ca
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #296 on: March 28, 2023, 01:39:56 am »
Code: [Select]
    // This operation can fail (if for example they are already owned), so returns a Result that can be an error or contain a value
    // we unwrap() it to get the inner value, and panic if it's an error instead.
    let cp = cortex_m::Peripherals::take().unwrap();

Code: [Select]
    // Configure the pin and take ownership of it (we borrow crh mutably from the port to make the change)
    let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);

If taking ownership could fail there, can it also fail here (as if the pin already has an owner)? If it cannot then why? If it can then why don't you use unwrap() here?
« Last Edit: March 28, 2023, 01:42:02 am by NorthGuy »
 

Offline ve7xen

  • Super Contributor
  • ***
  • Posts: 1194
  • Country: ca
    • VE7XEN Blog
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #297 on: March 28, 2023, 06:31:54 am »
Code: [Select]
    // This operation can fail (if for example they are already owned), so returns a Result that can be an error or contain a value
    // we unwrap() it to get the inner value, and panic if it's an error instead.
    let cp = cortex_m::Peripherals::take().unwrap();

Code: [Select]
    // Configure the pin and take ownership of it (we borrow crh mutably from the port to make the change)
    let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);

If taking ownership could fail there, can it also fail here (as if the pin already has an owner)? If it cannot then why? If it can then why don't you use unwrap() here?

Not at runtime, the static analysis of the borrow checker will guarantee it for us. That's not the case with take(), since it's not bound to an instance. What is happening with the GPIO pin pc13 is a 'singleton type' - the type system is used to store the details of the pin, and all its internals are private so it can't be constructed outside of the library. Since it can't be constructed, only one instance exists. into_push_pull_output is bound to the instance in the library, and calling it transfers ownership of that instance into into_push_pull_output, which then returns it to main where it is bound to led - main now owns the pin.

Exactly why take() is needed on the PAC is in the weeds and I'm not sure I fully understand it. I believe that it is because the borrow checker works on function calls, and you can't 'steal' variables. So ultimately we need a singleton gated by a function that transfers ownership of the protected state to make the whole thing work. If it were just a pub static variable, the borrow checker wouldn't protect us from multiple access. Once we've done it once as a function call, then that instance contains all the other singleton types like pc13 (exactly one), which we can borrow as we own the parent struct.
73 de VE7XEN
He/Him
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 27190
  • Country: nl
    • NCT Developments
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #298 on: March 28, 2023, 08:21:08 am »
But what if you want to share a GPIO pin because it has two functions depending on the mode of operation? Think about using a pin to configure and FPGA which after configuration gets a different function.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline uliano

  • Regular Contributor
  • *
  • Posts: 176
  • Country: it
Re: Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)
« Reply #299 on: March 28, 2023, 09:49:26 am »
But what if you want to share a GPIO pin because it has two functions depending on the mode of operation? Think about using a pin to configure and FPGA which after configuration gets a different function.

using rtic you can instantiate shared resources in the init, those resources can be accessed by different tasks. if the task run on the same priority no special care is required; otherwise you have to provide some kind of resouce contention mechanism, mutex or the like (I still have to test the resource sharing part... so take this with a grain of salt)

« Last Edit: March 28, 2023, 09:54:34 am by uliano »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf