Трансляция I2C и ответ на Arduino M0+

i2c

Я пытаюсь настроить несколько микросхем 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." );
}

, 👍1


2 ответа


1

Если вы передаете данные с помощью Wire.send(data), ведомые устройства получат это в обработчике onReceive, но, насколько я помню, ведомое устройство I2C не будет отвечать на широковещательную передачу Wire.requestFrom(...) от мастер.

Представьте, что x ведомых устройств одновременно отвечают на запрос...

,

0

Протокол I2C поддерживает арбитраж шины только для отправки мастеров (если более одного мастера в шине начинают отправлять одновременно). Таким образом, если какое-либо ведомое устройство действительно ответит на общий адрес вызова 0 данными, данные будут повреждены, если другое ведомое устройство также отправит данные. На этом фоне понятно, почему ведомое устройство I2C не отвечает на запрос по адресу общего вызова.

Если у вас слишком много чипов в шине или вы не хотите обращаться к Thema напрямую по другой причине, вы можете отправить триггерное сообщение на общий адрес вызова и позволить другим чипам отправлять свои данные в качестве мастеров. Имейте в виду, что в этом случае все задействованные микросхемы должны реализовать правильный арбитраж шины (и я не уверен, поддерживает ли это библиотека Wire ).

,