Трансляция I2C и ответ на Arduino M0+
Я пытаюсь настроить несколько микросхем AVR на базе ATSAM в схеме вещания ведущий/ведомый. Я хочу, чтобы мастер мог отправить широковещательное сообщение на адрес I2C 0, а затем подчиненные ответили другой информацией. Я видел другие реализации, в которых это было успешным, поскольку устройства I2C, как правило, выполняют самостоятельный арбитраж, и если они настроены на откат при потере арбитража, мастер может повторить свой запрос и выполнить итерацию по всем адресам на шине.
Проблема заключается в том, что хотя Wire.beginTransmission(0) работает, чтобы получить доступ к моим ведомым устройствам от мастера, я не могу заставить работать Wire.requestFrom(0,6). Подчиненный действует так, как если бы в случае ответа не было получено никакого сообщения. Это в сокращенном случае одного ведущего и одного ведомого.
В приведенном ниже примере сработает изменение RequestFrom на подчиненный адрес.
Я знаю, что в архитектуре SAMD ArduinoCore не настраивает SERCOM для широковещательной передачи I2C, поэтому я сделал однострочное изменение следующим образом, чтобы включить его:
sercom->I2CS.ADDR.reg = SERCOM_I2CS_ADDR_ADDR( ucAddress & 0x7Ful ) | // 0x7F, select only 7 bits
SERCOM_I2CS_ADDR_ADDRMASK( 0x00ul ) |
SERCOM_I2CS_ADDR_GENCEN // added by JAG
Мой мастер-код:
#include <Wire.h>
void setup() {
Serial.begin(9600);
Serial.println("Sketch start" );
Wire.begin(); // подключение к шине i2c (адрес необязателен для мастера)
}
byte x = 0;
void loop() {
Serial.print("-- Top of loop:" );
Serial.println( millis() );
Wire.beginTransmission(0); // передаем на устройство №8
Wire.write("x is "); // отправляет пять байт
Wire.write(x); // отправляет один байт
Wire.endTransmission(true); // прекращаем передачу
// delay( 500 );
uint8_t recvSize = Wire.requestFrom(0, 6); // запрашиваем 6 байт от ведомого устройства №8
Serial.print( "Got bytes: " );
Serial.print( recvSize );
Serial.print( "---> ");
while (Wire.available()) { // ведомое устройство может отправить меньше, чем запрошено
char c = Wire.read(); // получаем байт как символ
Serial.print( "[") ;
Serial.print(c); // напечатать символ
Serial.print( "]" );
}
Serial.println();
x++;
delay(500);
}
Мой подчиненный код:
#include <Wire.h>
void setup() {
Wire.begin(9); // присоединяемся к шине i2c с адресом #8
Wire.onReceive(receiveEvent); // регистрируем событие
Wire.onRequest(requestEvent); // регистрируем событие
Serial.begin(9600); // запускаем сериал для вывода
Serial.println( "Starting up" );
}
void loop() {
delay(500);
Serial.print( "In top of loop (slave): " );
Serial.println(millis() );
}
// функция, которая выполняется всякий раз, когда данные получены от мастера
// эта функция регистрируется как событие, см. setup()
void receiveEvent(int howMany) {
while (1 < Wire.available()) { // перебираем все, кроме последнего
char c = Wire.read(); // получаем байт как символ
SerialUSB.print(c); // напечатать символ
}
int x = Wire.read(); // получаем байт как целое
SerialUSB.println(x); // вывести целое число
}
// функция, которая выполняется всякий раз, когда мастер запрашивает данные
// эта функция регистрируется как событие, см. setup()
void requestEvent() {
Wire.write("hello"); // ответ сообщением из 6 байт
// как и ожидал мастер
Serial.println( "<<<< Writing a response." );
}
@Jeremy Gilbert, 👍1
2 ответа
Если вы передаете данные с помощью Wire.send(data), ведомые устройства получат это в обработчике onReceive, но, насколько я помню, ведомое устройство I2C не будет отвечать на широковещательную передачу Wire.requestFrom(...) от мастер.
Представьте, что x ведомых устройств одновременно отвечают на запрос...
Протокол I2C поддерживает арбитраж шины только для отправки мастеров (если более одного мастера в шине начинают отправлять одновременно). Таким образом, если какое-либо ведомое устройство действительно ответит на общий адрес вызова 0 данными, данные будут повреждены, если другое ведомое устройство также отправит данные. На этом фоне понятно, почему ведомое устройство I2C не отвечает на запрос по адресу общего вызова.
Если у вас слишком много чипов в шине или вы не хотите обращаться к Thema напрямую по другой причине, вы можете отправить триггерное сообщение на общий адрес вызова и позволить другим чипам отправлять свои данные в качестве мастеров. Имейте в виду, что в этом случае все задействованные микросхемы должны реализовать правильный арбитраж шины (и я не уверен, поддерживает ли это библиотека Wire ).
- Отправка и получение различных типов данных через I2C в Arduino
- Как работают функции вне цикла void?
- Как отображать переменные на 0,96-дюймовом OLED-дисплее с библиотекой u8glib?
- Как отправить строку на мастер с помощью i2c
- Как выбрать альтернативные контакты I2C на ESP32?
- Что означает в I2C «NACK получен»?
- NodeMCU с RFID RC522 и LCD-модулем интерфейса I2C вместе
- Несколько датчиков I2C с одинаковым адресом