Использование крейтов Rust для платы микроконтроллера STM32

В настоящее время я пытаюсь изучить Rust (в частности, для встроенных), исходя из опыта C для встроенных систем и Python. До сих пор я читал язык программирования Rust и Rust для встраиваемых систем и прочитайте несколько сообщений в блогах в Интернете.

Я хочу, чтобы мой первый проект был простым Blinky, где светодиод мигает бесконечно. У меня есть плата STM32L152CDISCOVERY с чипом STM32L152 (в основном таким же, как STM32L151), который представляет собой Cortex M3.

Вместо того, чтобы реализовывать все с нуля, я хочу использовать существующие ящики и HAL. Я нашел два многообещающих: stm32l1 и stm32l1xx-hal. Я пытался прочитать документацию каждого из них, а также часть исходного кода, но до сих пор не могу понять, как их правильно использовать.

Есть несколько вопросов о Rust и о ящиках:

  1. Я вижу, что stm32l1xx-hal зависит от stm32l1. Нужно ли мне добавлять оба в качестве зависимости в мой файл Cargo.toml? Или это создаст проблемы, связанные с правом собственности?

  2. Это правильный способ добавить их? Почему второй так добавлен [dependencies.stm32l1]?

    [dependencies]
    cortex-m-rt = "0.6.10"
    cortex-m-semihosting = "0.3.3"
    panic-halt = "0.2.0"
    stm32l1xx-hal = "0.1.0"
    
    [dependencies.stm32l1]
    version = "0.13.0"
    features = ["stm32l151", "rt"]
    
    
  3. Чтобы мигать LD4 (который подключен к PB4 PB6), я должен включить GPIOB в регистре RCC, а затем настроить контакт для двухтактного вывода. Просматривая документацию stm32l1xx-hal, я вижу, что есть Структура RCC и PB4 struct с помощью метода into_push_pull_output. Однако я до сих пор не понимаю, как использовать эти структуры: как их импортировать или как получить их экземпляр.

Я видел примеры кода для stm32l1, но не для stm32l1xx-hal. Я знаю, что я могу сделать это:

use stm32l1::{stm32l151};
...
let p = stm32l151::Peripherals::take().unwrap();
p.RCC.ahbenr.modify(|_,w| w.gpiopben().set_bit());

Но в исходниках stm32l1xx-hal я вижу, что часть RCC уже сделана в impl GpioExt for $GPIOX, но я не знаю, как добраться до функционала этой части.

Любая помощь, которая указывает мне правильное направление, приветствуется.


person Rafael Boy    schedule 22.05.2021    source источник


Ответы (1)


Я получил некоторую помощь от сообщества Discord. Ответы были (немного изменены мной):

  1. stm32l1xx-hal уже зависит от stm32l1, как см. здесь . Нет необходимости импортировать его дважды. Достаточно добавить в Cargo.toml:

    [dependencies.stm32l1xx-hal]
    version = "0.1.0"
    default-features = false
    features = ["stm32l151", "rt"]
    
    
  • Обратите внимание, что default-features = false является необязательным, но без него компилятор выдавал мне ошибку.
  1. Синтаксисы эквивалентны, но, как я сказал выше, мне нужно добавить только HAL. Вы можете добавить фигурные скобки {} в первый стиль, чтобы добавить параметры, такие как:

    stm32l1xx-hal = { version = "0.1.0", features = ["stm32l151", "rt"]}
    
    
  2. Правильный код для мигания (который был на PB6, а не на PB4, вздох):

    #![no_main]
    #![no_std]
    
    use panic_halt as _;
    
    use cortex_m_rt::entry;
    use stm32l1xx_hal::delay::Delay;
    use stm32l1xx_hal::gpio::GpioExt;
    use stm32l1xx_hal::hal::digital::v2::OutputPin;
    use stm32l1xx_hal::rcc::{Config, RccExt};
    use stm32l1xx_hal::stm32::Peripherals;
    use stm32l1xx_hal::stm32::CorePeripherals;
    use stm32l1xx_hal::time::MicroSeconds;
    
    
    #[entry]
    fn main() -> ! {
    
        let p = Peripherals::take().unwrap();
        let cp = CorePeripherals::take().unwrap();
    
        // Get LED pin PB6
        let gpiob = p.GPIOB.split();
        let mut led = gpiob.pb6.into_push_pull_output();
    
        // Set up a delay
        let rcc = p.RCC.freeze(Config::default());
        let mut delay = Delay::new(cp.SYST, rcc.clocks);
    
        loop {
    
            // Turn LED On
            led.set_high().unwrap();
    
            delay.delay(MicroSeconds(1_000_000_u32));
    
            // Turn LED Off
            led.set_low().unwrap();
    
            delay.delay(MicroSeconds(1_000_000_u32));
        }
    }
    
    
  • Для меня ключом было понять, что метод split можно вызывать из Peripherals, потому что stm32l1xx-hal реализует split для структуры, определенной в stm32l1. Другими словами, крейт HAL не только определяет новые структуры, но и расширяет функциональность существующих структур. Мне нужно обдумать шаблоны дизайна черт.
person Rafael Boy    schedule 29.05.2021