1

我正在尝试通过 SPI 协议与连接到 STM32L1(在NUCLEO-L152RE板上)的 BlueNRG 芯片(在X-NUCLEO-IDB04A1扩展板上)进行通信。

根据 BlueNRG手册,我可以发送一个 5 字节的空 SPI 数据包:(0x0B, 0, 0, 0, 0)以获取读/写缓冲区大小以及设备状态。状态应该是0x02(准备好),或者0x00设备0xFF是否正在睡眠并且正在唤醒。

这是我得到的通讯:

Send (0x0B, 0, 0, 0, 0)
Receive (0x00, 0x00)    // why 2 bytes?
Send (0x0B, 0, 0, 0, 0) // assuming device is waking up, re-trying
Receive (0x06, 0x00)    // what is code 6?

我的测试应用程序是使用Zinc用 Rust 编写的。MCU 正在运行默认时钟(来自 MSI 的 2048 MHz)。下面是负责 SPI 初始化的代码:

// PB.3 = CLCK
let _spi_clock = pin::Pin::new(pin::PortB, 3,
  pin::AltFunction(pin::AfSpi1_Spi2, pin::OutPushPull, pin::Medium),
  pin::PullDown);

// PA.6 = MISO
let _spi_in = pin::Pin::new(pin::PortA, 6,
  pin::AltFunction(pin::AfSpi1_Spi2, pin::OutPushPull, pin::Medium),
  pin::PullNone);

// PA.7 = MOSI
let _spi_out = pin::Pin::new(pin::PortA, 7,
  pin::AltFunction(pin::AfSpi1_Spi2, pin::OutPushPull, pin::Medium),
  pin::PullNone);

// PA.1 = CS
let spi_csn = pin::Pin::new(pin::PortA, 1,
  pin::GpioOut(pin::OutPushPull, pin::Medium),
  pin::PullUp);
spi_csn.set_high();

let spi = spi::Spi::new(spi::Spi1, spi::DirFullDuplex, spi::RoleMaster,
  spi::Data8b, spi::DataMsbFirst, 1); // baud pre-scaler = 2

let bnrg_reset = pin::Pin::new(pin::PortA, 8,
  pin::GpioOut(pin::OutPushPull, pin::VeryLow),
  pin::PullUp);

bnrg_reset.set_low();
// do something
bnrg_reset.set_high();

SPI 内部是从zinc master稍微修改的。发送/接收代码组织如下:

loop {
  spi_csn.set_low();
  // send a dummy read request
  spi.write(SpiRead as u8); // = 0x0B
  spi.write(0);
  spi.write(0);
  spi.write(0);
  spi.write(0);

  let status = spi.read();
  // debug print status
  while spi.has_more_data() {
    let data = spi.read();
    // debug print data
  }

  spi_csn.set_high();
}

问题是 -如何解释或处理这些 BlueNRG 响应?我无法找到它使用的低级协议的任何正式描述(这里不是在谈论 HCI/ACI,而是关于0x02= ready 以外的状态代码)。我很可能只是错误地初始化了硬件,或者甚至在这里遗漏了一些明显的东西。将不胜感激任何指导。

4

2 回答 2

3

SPI 驱动程序似乎存在根本问题。它在存储传入字节的硬件或软件中是否有缓冲区,或者它是如何工作的?通常您不使用 SPI 发送或接收,而是以全双工方式收发。SPI驱动本身无法判断传入的数据是有效的还是垃圾,所以不存在“发送5时我只收到2字节”之类的东西。发送 5 个字节时,您总是会收到 5 个字节。

此应用程序中的 MCU 将是 SPI 主机,外部芯片将是从机。对于发送的每个字节,您也会收到一个。该字节是否有意义取决于外部芯片的工作方式。遗憾的是没有 SPI 标准,因此外部芯片可以说明各种延迟要求,例如“在 SCK 和 MOSI 生效之前,必须将从选择拉低 x 个时间单位”。您必须详细阅读外部芯片的手册。

然后,当所有这些混乱都得到解决后,当 SPI 无法正常工作时,当然会有常见的怀疑:由于时钟极性或时钟相位设置不正确而导致的时钟偏差。

于 2014-11-21T09:05:54.537 回答
1

请参考 ST UM1865,第 5 章:SPI 接口。它适用于 BlueNRG-MS(不是 BlueNRG),但 HCI/ACI 接口是相同的。

如您所见,第一个字节是 SPI READY 指示,0x02 表示从属 SPI 接口已准备好。如果它是 0x02 以外的任何值,主机必须忽略后面的 4 个字节并中止 SPI 事务。

如果 BlueNRG(或 -MS)SPI 就绪 (0x02),则以下 4 个字节为写入和读取提供 2 个缓冲区大小:

  • 第 2 个字节包含写入缓冲区大小(最大值为 127)
  • 第 4 个字节包含读取缓冲区大小

在您的示例中, {0xb, 0, 0, 0, 0} 是 SPI 标头,仅用于检查 BlueNRG 的读取缓冲区大小。同样,{0xa, 0, 0, 0, 0} 是检查写缓冲区的大小。

如果返回的大小不是 0,例如在您的示例 {0x6, 0} 中,我认为它应该是 {0x6, 0, 0, 0},这意味着 BlueNRG 已准备好读取 6 (0 << 8 | 0x6) 字节的数据。然后,您应该尽快从 BlueNRG 中读取 6 个字节。

请参考 C:\Program Files (x86)\STMicroelectronics\BlueNRG DK 2.0.2\Projects\Drivers\BSP\STM32L1xx_BlueNRG\SDK_EVAL_Spi_Driver.c 了解函数 BlueNRG_SPI_Read_All()。

于 2018-02-12T08:28:45.143 回答