我正在试着从传感器上读取一个值,在覆盆子PI Pico上的SPI为BMP280.但我得到了意想不到的价值.

我在rp2040-project-template的基础上创建了一个新的repo,并对其进行了修改以添加SPI功能.

我添加了这些导入:

use embedded_hal::prelude::_embedded_hal_spi_FullDuplex;
use rp_pico::hal::spi;
use rp_pico::hal::gpio;
use fugit::RateExtU32;

然后在main函数的底部设置SPI:

let _spi_sclk = pins.gpio2.into_mode::<gpio::FunctionSpi>();
let _spi_mosi = pins.gpio3.into_mode::<gpio::FunctionSpi>();
let _spi_miso = pins.gpio4.into_mode::<gpio::FunctionSpi>();
let mut spi_cs = pins.gpio5.into_push_pull_output_in_state(PinState::Low); // initial pull down, for SPI

let spi = spi::Spi::<_, _, 8>::new(pac.SPI0);

let mut spi = spi.init(
    &mut pac.RESETS,
    clocks.peripheral_clock.freq(),
    10.MHz(),                           // bmp280 has 10MHz as maximum
    &embedded_hal::spi::MODE_0,
);

spi_cs.set_high().unwrap();   // pull up, set as inactive after init
delay.delay_ms(200);                     // some delay for testing

然后我试着读取ID注册表

spi_cs.set_low().unwrap();
let res_w = spi.send(0xd0 as u8); // 0xd0 is address for ID, with msb 1
let res_r = spi.read();
spi_cs.set_high().unwrap();

// check results
match res_w {
    Ok(_) => info!("write worked"),
    Err(_) => info!("failed to write")
}

match res_r {
    Ok(v) => info!("read value from SPI: {}", v),
    Err(_) => info!("failed to read SPI")
}

有了这个代码,SPI read fails.为什么会这样呢?

在读取ID之前,也许有必要在传感器上设置mode.我可以将此代码添加到读取的上面,设置为forced mode.

spi_cs.set_low().unwrap();
spi.send(0xf4-128 as u8).expect("failed to send first byte");  // registry 0xf4 with msb 0
spi.send(0x1 as u8).expect("failed to send second byte");
spi_cs.set_high().unwrap();

现在ID registry的读数起作用了,但我得到的值是255,而不是预期的0x58.

我做错了什么?


我也用这个代码try 了transfer:

let mut data: [u8; 2] = [0xd0, 0x0];
let transfer_success = spi.transfer(&mut data);
match transfer_success {
    Ok(v) => info!("read data {}", v),
    Err(_) => info!("failed to read")
}

但我在此代码中读取值为[255, 255],而不是预期的0x58.

推荐答案

read()可能不是您想要在这里使用的函数;它实际上并不执行任何总线操作,而只是给出在最后send()期间读取的字节.

您实际要使用的函数是transfer().在全双工SPI总线上,"读"操作always也是"写"操作,transfer同时执行这两个操作.请注意,如果您only想要读取,您需要write相同数量的零,因为只有总线主设备才能提供时钟来执行任何操作.

因此,如果您想写入0xd0,然后读取单个字节,则需要将值[0xd0, 0x00]设置为transfer().然后,您用来将发送的数据放入transfer()same array将包含接收的数据;很可能是[0x00, <data>](或[0xff, <data>],不确定).可能是0xff,正如你已经提到的,你读的是255).

implementation of transfer表示read()应该如何使用actually:

fn transfer<'w>(&mut self, words: &'w mut [W]) -> Result<&'w [W], S::Error> {
    for word in words.iter_mut() {
        block!(self.send(word.clone()))?;
        *word = block!(self.read())?;
    }

    Ok(words)
}

注意,在这里嵌入的block!()个异步调用通常返回一个错误,指示操作将被阻塞,直到它完成.block!()宏将异步调用转换为阻塞调用,这很可能是错误的来源.

无论哪种方式,我都建议您从official example派生代码,它们通常很好地演示了对象的预期使用方式.

Rust相关问答推荐

如果A == B,则将Rc A下推到Rc B

在跨平台应用程序中使用std::OS::Linux和std::OS::Windows

如何高效地将 struct 向量中的字段收集到单独的数组中

为什么TcpListener的文件描述符和生成的TcpStream不同?

如何实现Serde::Ser::Error的调试

Rust中WPARAM和VIRTUAL_KEY的比较

对于rustc编译的RISC-V32IM二进制文件,llvm objdump没有输出

为什么rustc会自动降级其版本?

Rust 中什么时候可以返回函数生成的字符串切片&str?

使用占位符获取用户输入

如何处理闭包中的生命周期以及作为参数和返回类型的闭包?

为什么我的trait 对象类型不匹配?

如何从trait方法返回std :: iter :: Map?

如何在 Rust 中将 Vec> 转换为 Vec>?

为什么 File::read_to_end 缓冲区容量越大越慢?

如何在 Rust 中将 UTF-8 十六进制值转换为 char?

如何在 use_effect_with_deps 中设置监听器内的状态?

Rust 内联 asm 中的向量寄存器:不能将 `Simd` 类型的值用于内联汇编

如何从 Rust 中不同类型的多个部分加入 Path?

为什么我返回的 impl Trait 的生命周期限制在其输入的生命周期内?