antoinevg / daisy_bsp

Board support package for the Electro-Smith Daisy Seed.
MIT License
67 stars 13 forks source link

Question: How do I sample values from knobs? #1

Closed andrewjensen closed 3 years ago

andrewjensen commented 3 years ago

Hi, thanks so much for this crate and for your ADC talk!

I've done some Arduino and some Rust, but I'm new to embedded Rust, so I'm not used to the lower levels of abstraction. I'm having a hard time understanding how to use analog-to-digital converters to sample values from knobs. I think I should be using stm32h7xx_hal::adc::Adc but I'm getting lost in the docs as to how to do that. Could you point me in the right direction?

EDIT: I have a Daisy Pod so I believe POT 1 maps to board.pins.SEED_21 in the board support crate.

antoinevg commented 3 years ago

I'm still in the process of adding explicit support for the Daisy Pod's peripherals, but for now you can check out this quick example of stm32h7xx_hal::adc::Adc that will work with it:

https://github.com/antoinevg/daisy_bsp/blob/main/examples/adc_hal.rs

andrewjensen commented 3 years ago

Thank you for creating the example, that's very helpful! I tried uploading the example code to my board and it worked great.

The next thing I want to do is to run the BSP's audio interface and react to the knob values, but this code never seems to run, so I think it is panicking on startup:

    let cp = cortex_m::Peripherals::take().unwrap();
    let dp = pac::Peripherals::take().unwrap();
    let board = daisy::Board::take().unwrap();
    // (I narrowed it down to these three lines that cause the startup issue)

    // ...

Looking at the source for Board::take, I see that the board is internally calling take on those peripherals as well, so maybe including both the high-level and low-level calls is causing a panic. Is there a way to engineer around this, or does this mean that I need to use only daisy_bsp or only stm32h7xx-hal?

antoinevg commented 3 years ago

The underlying reason for the panic is that cortex_m::Peripherals and pac::Peripherals are implemented as global singletons.

This means they'll cause a panic! when daisy::Board tries to instantiate them for a second time.

The valuable part of this approach is that it allows us to use the Rust type system to enforce various safety constraints on hardware access.

For instance, in this case, we are protected from a situation where a board support crate (e.g. daisy::Board) could overwrite or conflict with any configuration you performed using the HAL (e.g. stm32h7xx-hal) crate.

Unfortunately, the price we pay is that we now have to wait for the author of higher level abstractions (like board support crates) to expose any unsupported peripherals for us because we no longer have direct access to the HAL. 🤨

Luckily there are a couple of escape hatches we can use while waiting for crate authors to get their act together!

The first of these escape hatches is a way to get direct access to the cortex_m::Peripherals and pac::Peripheral singletons.

We can do this using the unchecked steal() method after daisy::Board initialization has completed:

let mut board = daisy::Board::take().unwrap();
let cp = unsafe { cortex_m::Peripherals::steal() };
let dp = unsafe { pac::Peripherals::steal() };

The second escape hatch you'll need to work with HAL API's within the context of the BSP crate is access to the ccdr.peripheral (Core Clock Distribution and Reset + Peripheral reset/enable/kernel clock control) singleton.

Usually you'd obtain the ccdr object from configuring and freezing the power & clock configuration for the MCU:

let mut ccdr = dp.RCC.constrain() ... freeze(pwrcfg, &dp.SYSCFG); 

However we're using the board support package to do this for us which means we can no longer get at it!

So I'm still exploring the best way of doing this but for now I've pushed a new version of the crate which moves ownership to thedaisy::Board object after initialization is complete.

This will let us do things like:

// switch adc_ker_ck_input multiplexer to per_ck
board.peripheral.kernel_adc_clk_mux(AdcClkSel::PER);

Of course none of this is ideal and due caution should certainly be exercised but it's a good stopgap.

Finally, I've put together an example here: https://github.com/antoinevg/daisy_bsp/blob/main/examples/adc_bsp.rs

(Note that you'll need to bump your daisy_bsp version to 0.2.0 to compile the example)

andrewjensen commented 3 years ago

Thanks so much for the new release and the detailed help! I was able to get both the pots and the audio interface working.

Of course none of this is ideal and due caution should certainly be exercised but it's a good stopgap.

I can see how it's difficult to determine how much a board support package should abstract away, and how to expose functionality in a way that has good defaults but is still extensible. I'm excited to see where you take the crate, thanks again for putting it together!

HazelSh commented 3 years ago

Thanks as well, I was having some trouble figuring out this exact issue -- knob reads on the daisy pod. I'll take a look at the new examples in the new release. I appreciate the work you're putting in on this :)

antoinevg commented 3 years ago

Update: I've refactored the board API's somewhat to remove the root cause of the ownership issues.

You can check out the updated adc example to get an idea of how it works now:

https://github.com/antoinevg/daisy_bsp/blob/main/examples/adc_bsp.rs