Неизвестный ответ BlueNRG SPI

Я пытаюсь связаться с чипом BlueNRG (на плате расширения X-NUCLEO-IDB04A1), подключенным к STM32L1 (на плате NUCLEO-L152RE) по протоколу SPI.

Согласно инструкции BlueNRG, я могу отправить пустой пакет SPI из 5 байтов: (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?

Мое тестовое приложение написано на Rust с использованием Zinc. На MCU установлены часы по умолчанию (2048 МГц от MSI). Вот код, отвечающий за инициализацию 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 слегка модифицированы по сравнению с цинковым мастером. Код отправки / получения организован следующим образом:

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 = готово). Вполне возможно, что я просто неправильно инициализирую аппаратное обеспечение или даже пропускаю что-то очевидное здесь. Буду признателен за любые рекомендации.

2 ответа

Решение

Кажется, что-то не так с драйвером SPI. Есть ли в аппаратном или программном обеспечении буфер, в котором хранятся входящие байты, или как он работает? Как правило, вы не отправляете и не получаете с SPI, вы принимаете в полном дуплексе. Для самого драйвера SPI будет невозможно определить, являются ли входящие данные действительными или мусорными, поэтому не существует такой вещи, как "Я получаю только 2 байта при отправке 5". Вы всегда получаете 5 байтов при отправке 5 байтов.

MCU в этом приложении будет ведущим SPI, а внешний чип будет ведомым. За каждый отправленный байт вы также получите один. Имеет ли смысл этот байт, зависит от того, как работает внешний чип. К сожалению, нет стандарта SPI, поэтому внешний чип может указывать различные требования к задержке, такие как, например, "выбор ведомого устройства должен быть установлен на низкое значение для x единиц времени, прежде чем SCK & MOSI будут запущены". Вам придется подробно прочитать руководство по эксплуатации внешнего чипа.

И затем, когда вся эта путаница улажена, есть, конечно, обычные подозрения, что SPI не работает должным образом: перекос тактовой частоты из-за неправильной полярности тактовой частоты или настроек фазы тактовой частоты.

Пожалуйста, обратитесь к ST UM1865, Глава 5: Интерфейс SPI. Это для BlueNRG-MS (не BlueNRG), но интерфейс HCI/ACI такой же.

Как вы заметили, 1-й байт является индикатором готовности SPI, а 0x02 указывает, что подчиненный интерфейс SPI готов. Если это значение равно 0x02, мастер должен игнорировать следующие 4 байта и прервать транзакцию SPI.

Если SPI BlueNRG (или -MS) готов (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) байтов данных. Затем вы должны прочитать 6 байтов из BlueNRG, как только сможете.

Пожалуйста, обратитесь к C:\Program Files (x86)\STMicroelectronics\BlueNRG DK 2.0.2\ Проекты \ Драйверы \BSP\STM32L1xx_BlueNRG\SDK_EVAL_Spi_Driver.c для функции BlueNRG_SPI_Read_All().

Другие вопросы по тегам