Когда требуется SPI.beginTransaction?
Я постепенно переводил многие устройства с i2c на spi по разным причинам. Я заметил, что в подобных учебниках из arduino.cc эта транзакция SPI.beginTransaction
вызывается явно. Затем они ссылаются на такие примеры, как this и this, где они не используют SPI.beginTransaction
. Работая с помощью своих собственных устройств, я обнаружил, что часто (почти всегда) могу отказаться от использования SPI.beginTransaction
. Единственный случай, когда я обнаружил проблемы, был, когда у меня было 2 устройства, которые использовали разные настройки SPI.
Я зашел в Google и другие поисковые системы в поисках простой причины для SPI.beginTransactions
и нашел обсуждения прерываний, блокировок и настроек. Было много дискуссий о том, что пользовательские приложения оборачивают все вызовы с помощью SPI.beginTransaction
и SPI.endTransaction
. Были ошибки, когда библиотеки не оборачивались повсюду.
Это приводит меня к выводу, что вызовы SPI.beginTransaction
необходимы только тогда, когда необходимо изменить настройки SPI, но на практике вы всегда должны это делать. Есть ли документация или примеры, в которых определенно указывается цель и правильное (наилучшая практика) ее использования?
@Matt, 👍6
3 ответа
Лучший ответ:
Хотя на этот вопрос есть общепринятый ответ, я хотел бы привести некоторые предпосылки и исторические причины вопроса OP.
Транзакционный SPI с использованием SPI.beginTransaction()
был представлен в 2014 году, он не был доступен в ранней версии ардуино или в примерах кодов, опубликованных до этого. Как показывают результаты, в Интернете все еще существует множество кодов, показывающих старый способ настройки конфигурации SPI, и это включает примеры, предоставленные Arduino.cc на своей справочной странице библиотеки даже до сегодняшнего дня авторы библиотеки не вносили никаких изменений в эти примеры, чтобы показать использование нового API.
Что делает SPI.beginTransaction()
, так это позволяет вам устанавливать уникальные настройки SPI (через объект SPISettings) для вашего приложения, даже если другие устройства используют другие настройки.
SPI.beginTransaction()
ведет себя как механизм блокировки, чтобы получить эксклюзивное использование шины SPI, и поэтому требует, чтобы SPI.endTransaction()
освободил шину для доступа к ней других пользователей. SPI.beginTransaction()
обеспечивает лучшую совместимость между устройствами и разрешает программные конфликты, а также позволяет нескольким устройствам SPI правильно использовать шину SPI. Поэтому вам следует использовать SPI.beginTransaction()
в вашем скетче SPI. Вы также должны использовать объект SPISettings для настройки вашего интерфейса связи SPI и не использовать устаревшие методы, такие как
SPI.setBitOrder()
, SPI.setClockDivider()
и SPI.setDataMode()
для настройки конфигурации SPI.
Хотя сегодня это редко требуется, в библиотеке SPI есть предопределенная макрокоманда SPI_HAS_TRANSACTION для проверки, поддерживает ли прошивка платы Arduino
SPI.beginTransaction()
. Это полезно для обеспечения обратной совместимости, если вы пишете библиотеку Arduino.
#ifdef SPI_HAS_TRANSACTION
SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
#elseif
// используйте старый синтаксис библиотеки Arduino SPI
#endif
Похоже, что вызов метода beginTransaction() предотвращает прерывание текущей транзакции дополнительными транзакциями SPI. Вызов endTransaction() снова разрешает доступ к оборудованию SPI. Эта дополнительная сложность может показаться странной. Особенно в простой парадигме написания скетчей Arduino. Но по мере усложнения программ добавляется все больше устройств SPI и используются прерывания для быстрого доступа к устройствам SPI - вероятность конфликта SPI возрастает.
В исходном кодеSPIClass непосредственно перед методом beginTransaction() есть такой комментарий:
// Перед использованием SPI.transfer() или утверждением выводов выбора микросхемы,
// эта функция используется для получения эксклюзивного доступа к шине SPI
// и настройте правильные настройки.
Таким образом, может случиться так, что если sketch-код особенно хорошо себя ведет и не нуждается в защите от случайного использования аппаратного обеспечения SPI от нескольких одновременных транзакций, то эти два метода не нужно использовать. Но зачем рисковать?
Каждая современная библиотека Arduino для устройства SPI должна использовать библиотеку SPI с beginTransaction, чтобы иметь возможность сосуществовать с библиотеками для устройств SPI, используя разные режимы и скорость.
Недавно у нас возник вопрос о том, что две библиотеки для SPI не работают вместе. Устройства требовали разных режимов. Библиотеки не использовали beginTransaction, они использовали только SPI.begin() при инициализации. Невозможно использовать эти библиотеки вместе.
Ядро STM32 поддерживает переключение CS pin с улучшенными beginTransaction и endTransaction, но это не так полезно, как кажется. Многие устройства используют CS в качестве "фиксации", и CS необходимо переключать несколько раз внутри одной "транзакции".
Если вы пишете библиотеку, вы не знаете, с какими другими устройствами SPI на шине она будет использоваться, поэтому вызывайте beginTransaction
, когда библиотека получает управление, и endTransaction
, когда функция публичной библиотеки возвращает управление из библиотеки.
- Как использовать SPI на Arduino?
- Как увеличить скорость записи на SD-карту в Ардуино
- Как считывать данные с помощью Arduino SPI
- Как передать более 1 байта сразу по шине SPI?
- OVF в последовательном мониторе вместо данных
- Как отправить строку с подчиненного устройства Arduino с помощью SPI?
- Проблема совместного использования MISO с несколькими RFID-считывателями RC522
- Путаница между SPI и I2C для SSD1306 OLED