You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌入式Rust中运行时将SPI引脚重配置为GPIO的实现方法

STM32H7 HAL中SPI MOSI引脚动态切换为GPIO输出的实现方案

问题背景

基于STM32H7xx HAL开发电路板时,存在SPI3外设控制多个组件的场景,但其中一个设备需要复用SPI3的MOSI引脚作为普通GPIO驱动。需要完成psu_13v8_ctrl函数中引脚重配置的TODO部分。

核心思路

要实现引脚的动态切换,必须将SPI实例拆分为总线控制部分和独立引脚,这样才能释放MOSI引脚进行GPIO配置;操作完成后再将引脚恢复为SPI复用功能,重新初始化SPI外设。

修改后的完整代码

use cortex_m::prelude::_embedded_hal_blocking_spi_Write;
use stm32h7xx_hal::{
    spi::{Enabled, Spi, SpiBus},
    gpio::{Output, Pin, PushPull, Alternate, Speed},
    pac::SPI3,
    embedded_hal::spi::Mode,
};

// 根据实际硬件定义SPI3 MOSI引脚的复用类型
// 示例:PD6引脚,复用功能AF6对应SPI3 MOSI(需和硬件手册匹配)
type Spi3MosiPin = Pin<'D', 6, Alternate<6, PushPull>>;

pub struct ShiftRegSelector {
    up_ciod_sh_reg_sel0: Pin<'D', 10, Output<PushPull>>,
    up_ciod_sh_reg_sel1: Pin<'D', 11, Output<PushPull>>,
    up_ciod_sh_reg_n_latch: Pin<'E', 10, Output<PushPull>>,
    up_ciod_sh_reg_n_rst: Pin<'E', 15, Output<PushPull>>,
    spi_bus: SpiBus<SPI3, Enabled>,
    mosi: Spi3MosiPin,
    spi_mode: Mode,
    spi_baud_rate: u32,
}

impl ShiftRegSelector {
    pub fn new(
        up_ciod_sh_reg_sel0: Pin<'D', 10, Output<PushPull>>,
        up_ciod_sh_reg_sel1: Pin<'D', 11, Output<PushPull>>,
        up_ciod_sh_reg_n_latch: Pin<'E', 10, Output<PushPull>>,
        up_ciod_sh_reg_n_rst: Pin<'E', 15, Output<PushPull>>,
        spi: Spi<SPI3, Enabled>,
    ) -> Self {
        // 拆分SPI为总线控制单元和独立引脚
        let (spi_bus, pins) = spi.split();
        // 保存原始SPI配置参数,用于后续恢复
        let spi_mode = spi.mode();
        let spi_baud_rate = spi.baud_rate();

        Self {
            up_ciod_sh_reg_sel0,
            up_ciod_sh_reg_sel1,
            up_ciod_sh_reg_n_latch,
            up_ciod_sh_reg_n_rst,
            spi_bus,
            mosi: pins.mosi,
            spi_mode,
            spi_baud_rate,
        }
    }

    pub fn psu_13v8_ctrl(&mut self, enable: bool) {
        // 1. 禁用SPI外设,释放MOSI引脚
        let (spi_bus_disabled, mosi_pin) = self.spi_bus.disable(self.mosi);
        self.spi_bus = spi_bus_disabled;

        // 2. 将MOSI引脚重配置为GPIO推挽输出
        let mut mosi_gpio = mosi_pin.into_push_pull_output(Speed::High);

        self.reset_mux();

        // 3. 根据需求驱动GPIO电平
        if enable {
            mosi_gpio.set_high();
        } else {
            mosi_gpio.set_low();
        }
        
        self.latch_mux();
        self.reset_mux();

        // 4. 将GPIO恢复为SPI复用功能(注意复用功能号要匹配硬件)
        let mosi_spi = mosi_gpio.into_alternate::<6, PushPull>();

        // 5. 重新启用SPI外设,恢复原始配置
        self.spi_bus = self.spi_bus.enable(mosi_spi, self.spi_mode, self.spi_baud_rate);
        self.mosi = self.spi_bus.pins().mosi;
    }

    fn latch_mux(&mut self) {
        self.up_ciod_sh_reg_sel0.set_high();
        self.up_ciod_sh_reg_sel1.set_high();
        self.up_ciod_sh_reg_n_latch.set_low();
    }
    
    fn reset_mux(&mut self) {
        self.up_ciod_sh_reg_n_rst.set_high();
        self.up_ciod_sh_reg_n_latch.set_high();
    }
    
    pub fn something(&mut self) {
        // 临时组合SPI总线和引脚,执行写操作
        let mut spi = Spi::from_bus(self.spi_bus, self.mosi);
        spi.write(&[0x11u8, 0x22, 0x33]).unwrap();
        // 拆分回总线和引脚,保存回结构体
        let (bus, pins) = spi.split();
        self.spi_bus = bus;
        self.mosi = pins.mosi;
    }
}

关键细节说明

  • SPI拆分与重组:STM32H7 HAL的Spi实例可以通过split()拆分为SpiBus(总线控制)和独立引脚,操作完成后用from_bus()重新组合,这是实现引脚动态切换的核心。
  • 引脚复用配置:转换GPIO到SPI复用功能时,必须指定正确的Alternate功能号(示例中为AF6),需严格匹配硬件手册中SPI3 MOSI引脚的复用定义。
  • 状态保存:必须保存SPI的原始模式(CPOL/CPHA)和波特率,否则恢复后的SPI无法正常工作。
  • 引脚速度:配置GPIO输出时指定的速度(示例中为Speed::High)需根据硬件驱动能力调整。

内容的提问来源于stack exchange,提问作者Dushara

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 05:23:16