Embedded_hal: how to "split off" objects

I'm trying to write a program for a STM32F030, and right now I'm using the stm32f0xx_hal crate.

The support for gpio and for serial has been great, but now I want to use a timer, and it's less easy to do what I want. I think I can do what I want by using the non-hal options, but I can't figure out how to do this.

Here is an example, which I think should blink. Obviously, my real code is doing more, this is just something minimal to show the problem.

#![no_main] //  Don't use the Rust standard bootstrap. We will provide our own.
#![no_std] //  Don't use the Rust standard library. We are building a binary that can run on its own.

extern crate cortex_m;
extern crate cortex_m_rt; //  Startup and runtime functions for ARM Cortex-M3.
extern crate panic_halt;
extern crate stm32f0xx_hal;
extern crate embedded_hal;
use embedded_hal::digital::v2::OutputPin;

use crate::hal::{prelude::*, stm32};
use cortex_m_rt::entry;
use stm32f0xx_hal as hal;

#[entry]
fn main() -> ! {
    if let Some(mut p) = stm32::Peripherals::take() {
        // Set things up
        let mut out =
            cortex_m::interrupt::free(|cs| {
                let mut rcc = p.RCC.configure().sysclk(40.mhz()).freeze(&mut p.FLASH);

                let gpiob = p.GPIOB.split(&mut rcc);

                gpiob.pb4.into_push_pull_output(cs)
            });

        // Enable the timer
        p.TIM3.cr1.write(|w| w.cen().enabled());

        loop {
            if p.TIM3.cnt.read().cnt().bits() > 10000 {
                let _ = OutputPin::set_low(&mut out);
            } else {
                let _ = OutputPin::set_high(&mut out);
            }
        }
    }
    loop {}
}

This doesn't compile because p is used in the interrupt::free function (which is required to set up the output pin), but then I need to access p to mess around with the timer.

With GPIO, the trick is basically to ".split" the gpio pins of the main peripherals, and then you can move them however you want. But the TIM3 object doesn't have a split function, nor can I find anything else that works.

Is it possible to fix this?
My guess is that I would need to use an unsafe block to split off the TIM3, but I'd like to avoid that approach if possible.

Ok, I figured it out, and I'll paste my solution here in the hope that it doesn't take the next guy 4 days. You just reference it as an unsafe option.

Here is some sample code for blinking a led on a STM32F030F4P6 demo board. It's not the best way to blink the led, but I'll leave it here to demonstrate how to use a timer:

#![no_main] //  Don't use the Rust standard bootstrap. We will provide our own.
#![no_std] //  Don't use the Rust standard library. We are building a binary that can run on its own.

extern crate cortex_m;
extern crate cortex_m_rt; //  Startup and runtime functions for ARM Cortex-M3.
extern crate panic_halt;
extern crate stm32f0xx_hal;

use crate::hal::{prelude::*, stm32};
use cortex_m_rt::entry;
use hal::stm32::{TIM3, RCC};
use stm32f0xx_hal as hal;

#[entry]
fn main() -> ! {
    if let Some(mut p) = stm32::Peripherals::take() {
        // Set things up
        let mut out = cortex_m::interrupt::free(|cs| {
                let mut rcc = p.RCC.configure().sysclk(40.mhz()).freeze(&mut p.FLASH);
                let gpioa = p.GPIOA.split(&mut rcc);

                gpioa.pa4.into_push_pull_output(cs)
            });

        // You can access the registers using unsafe
        unsafe {
            (*RCC::ptr()).apb1enr.write(|w| w.tim3en().set_bit()); // Enable the timer
            (*TIM3::ptr()).sr.write(|w| w.bits(0)); // Clear something (recommended by app notes)
            (*TIM3::ptr()).arr.write(|w| w.bits(0x2FFF)); // Set the max. value to which it will count
            (*TIM3::ptr()).psc.write(|w| w.bits(5000)); // Divide the input clock by this much
            (*TIM3::ptr()).cr1.write(|w| w.cen().set_bit()); // Enable the clock
        }

        loop {
            let x = unsafe{(*TIM3::ptr()).cnt.read().cnt().bits()}; // Read the value from the counter

            // Set the output on the LED pin
            if x > 1000 {
                out.set_high(); 
            } else {
                out.set_low();
            }

        }
    }
    loop {}
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.