Неизвестный ответ 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().