Add a project-specific driver to a hal crate

I use the crate stm32f3xx_hal in my embedded project. Now I have to add my own drivers for certain problems. For example I need the compare function of a timer. How do I do this?

My attempt to add a driver in my project failed, because many functions are crate-locally defined. Example:

pub fn new(tim: TIM2, resolution: u32, clocks: Clocks, apb: &mut APB1) -> CompareTimer { 
        apb.enr().modify(|_, w| w.tim2en().set_bit());
        apb.rstr().modify(|_, w| w.tim2rst().set_bit());
        apb.rstr().modify(|_, w| w.tim2rst().clear_bit());

        let pclk1 = clocks.pclk1();
        let timer_clock = pclk1.0 * if clocks.ppre1() == 1 { 1 } else { 2 }; // z.B. 8_000_000
        let psc = (timer_clock / 1_000_000) * resolution - 1; // z.B. 1000µs => psc = 7999

        tim.psc.write(|w| w.psc().bits(psc as u16));

        // test ccr1
        tim.ccr1.write(|w| w.ccr().bits(500));            // ccr to 500

        // Trigger an update event to load the prescaler value to the clock
        // NOTE(write): uses all bits in this register.

        let compare_timer = CompareTimer {clocks: clocks, tim: tim };
        // The above line raises an update event which will indicate that the timer is already 
        // finished. Since this is not the case, it should be cleared

For example the function apb.enr() is not accessible from outside. The only way I found to implement this is to integrate the sources of the crate stm32f3xx_hal into the project and patch them.

But I find this very unattractive, because I want to use this crate as it is provided by the community. Are there any alternatives to this?

Thank you

You could fork the HAL crate and submit a PR to include what you need in the next release

1 Like

Thank you for your answer.

Yes, I could do that

  • For that I would have to be able to formulate my requirement in a general usable solution including macros for all derivatives of this hal. That is a lot of work and besides I am not able to do that.
  • This also assumes that my specific problem is of general interest. This will also often not be the case.

In serious projects it will regularly be the case that the standard hal crate is not comprehensive enough. In my opinion it would be desirable to have a provided way to extend the driver specifically.

What you'll need to do is use the pac directly.

use stm32f3xx_hal::pac::RCC;

pub fn new( ) -> Self {
    let rcc = unsafe { &*RCC::ptr( ) };
    rcc.apb1enr.modify( | _, w | w.tim2en( ).enabled( ) );

    // Other initialization stuff..

You'll end up using a combination of abstractions provided by the device crate and peripherals from the svd2rust crate (exposed via stm32f3xx_hal::pac).

Thanks for the tip. This looks good.