Почему SPI читает только 0xFF?
Обновлено Редакция GAW
В SPI ведомое устройство отвечает, только когда выбрано своим сигналом CS и получает такты от ведущего. Пока оно не выбрано, его выход MISO отключён, и на линии остаётся то, что задаёт подтяжка или соседнее устройство. Поэтому 0xFF и 0x00 в каждом байте — признак того, что обмена фактически нет, а не испорченных данных.
| Что читается | Вероятная причина | Что проверить |
|---|---|---|
| 0xFF всегда | ведомый не выбран или не понял команду | CS опускается на всё время транзакции, бит чтения в адресе |
| 0x00 всегда | MISO прижата или выбраны два устройства | CS остальных ведомых в единице, нет замыкания |
| Данные сдвинуты на бит (0x7F вместо 0xFE) | не тот режим CPOL/CPHA | режим по временной диаграмме даташита |
| Ведущий внезапно молчит | низкий уровень на SS/NSS ведущего | SS настроен выходом или NSS программный |
| Первый байт мусор, дальше верно | этот байт пришёл, пока передавалась команда или адрес | пропустить первый принятый байт |
Ведущий должен тактировать
Ведущий выдаёт такты только во время передачи. В reference manual STM32 RM0008 сказано прямо: передача начинается записью байта в буфер передачи, а принятый байт одновременно попадает в буфер приёма. Чтобы прочитать байт, нужно отправить фиктивный.
Ведущий, ставший ведомым
У AVR и STM32 есть защита от двух ведущих на шине. Если у ATmega328P вывод SS настроен как вход и на нём ноль, модуль SPI сбрасывает бит MSTR и становится ведомым. У STM32 то же самое называется ошибкой MODF. Вывод SS/NSS ведущего настраивают выходом или переводят в программный режим; у STM32 есть и третий вариант — аппаратный NSS как выход (бит SSOE).
Команда чтения
Многие датчики кодируют чтение старшим битом адреса. У BME280 управляющий регистр 0xF4 (ctrl_meas) читают, передавая 0xF4, а записывают, передавая 0x74. Если бит чтения не выставить, датчик воспримет запрос как запись и ничего не вернёт.
Режим тактирования по даташиту определяют по инструкции в ответе «Как узнать режим SPI по даташиту?», четыре режима разобраны в термине «режимы SPI», а посмотреть кадр по битам поможет диаграмма кадра SPI. Основы шины — на странице SPI.
Похожие вопросы
Почему SPI читает 0x00, а не 0xFF?
Если MISO прижата к нулю — подтяжкой вниз, замыканием или вторым устройством на шине, которое тоже выбрано, — читаются нули. Проверьте, что одновременно опущен только один CS и что у неиспользуемых ведомых CS в единице.
Зачем передавать байт, если нужно только прочитать?
В SPI ведущий сам выдаёт такты, а такты идут, только пока он передаёт. По RM0008 обмен начинается записью байта в буфер передачи, и принятый байт появляется одновременно с отправленным. Поэтому для чтения передают фиктивный байт, обычно 0x00 или 0xFF.
Почему Arduino перестаёт быть ведущим SPI?
Если вывод SS (D10 на Uno) настроен как вход и на нём оказался ноль, по даташиту ATmega328P модуль SPI сбрасывает бит MSTR и становится ведомым. Поэтому D10 держат выходом, даже если CS устройства подключён к другому выводу.
Источники
- STMicroelectronics. RM0008 Rev 21. Reference manual: STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx — разд. 25.3.3 — в режиме ведущего передача начинается при записи байта в буфер передачи, принятый байт попадает в буфер приёма с флагом RXNE; NSS в аппаратном режиме входа держат в единице, в программном режиме ставят SSM и SSI; MSTR и SPE остаются установленными, только если NSS в единице; разд. 25.3.10 — ошибка MODF при низком NSS у ведущего: сбрасываются SPE и MSTR, модуль становится ведомым; разд. 25.3.1 — при SSOE = 1 вывод NSS ведущего работает выходом
- Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B) — разд. 19.3.1 — ведомый при высоком SS не принимает данные, все его выводы — входы; разд. 19.3.2 — если у ведущего SS настроен как вход и опущен в ноль, бит MSTR сбрасывается и SPI становится ведомым, MOSI и SCK превращаются во входы
- Bosch Sensortec. BME280 Combined humidity and pressure sensor: Data sheet (BST-BME280-DS001-24, revision 1.24, February 2024) — разд. 6.3 — в SPI старший бит адреса регистра заменён битом чтения/записи: для чтения регистра передают его полный адрес (0xF7), для записи — адрес без старшего бита (0x77); разд. 5.4.5 — управляющий регистр ctrl_meas по адресу 0xF4
Нашли ошибку?