Связь I2C между arduino и raspberry pi прерывается по непонятным причинам. Почему?
У меня возникает поведение, которое я не могу объяснить при использовании arduino mega в качестве подчиненного устройства I2C для главного устройства Raspberry Pi.
Здесь я показываю идеализированную программу, которая показывает проблему. Я испытываю примерно такое же поведение в реальном приложении (прошивка клавиатуры). Я делаю следующее:
- arduino выдает прерывание на контакте 23 в каждом цикле, чтобы сообщить raspi, что есть данные для чтения.
- raspi отправляет запрос в качестве мастера на arduino.
- arduino получает запрос в обработчике Wire и выдает ответ размером 32 байта. Я заполняю эти 32 байта счетчиком uint8 просто для проверки.
- цикл начинается снова.
Это код для raspi
import time
import RPi.GPIO as GPIO
import smbus
GPIO.setmode(GPIO.BCM)
GPIO.setup(4, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
bus = smbus.SMBus(1)
address = 0x42
def callback(channel):
data = bus.read_i2c_block_data(address, 0x00, 32)
print(data)
GPIO.add_event_detect(4, GPIO.RISING, callback=callback)
while True:
time.sleep(1)
GPIO.cleanup()
а это код Arduino
#include <Wire.h>
byte IRQ_PIN = 23;
volatile unsigned int counter;
void setup() {
Serial.begin(115200);
pinMode(IRQ_PIN, OUTPUT);
digitalWrite(IRQ_PIN, LOW);
Wire.begin(0x42);
Wire.onRequest(requestEvent);
Wire.onReceive(receiveData);
}
void signalMaster() {
noInterrupts();
irq();
interrupts();
}
void irq() {
digitalWrite(IRQ_PIN, HIGH);
digitalWrite(IRQ_PIN, LOW);
}
void requestEvent() {
byte buf[32];
counter++;
memset(buf, counter, 32*sizeof(byte));
Wire.write(buf, 32);
}
void receiveData(int byteCount){
while(Wire.available()) {
Wire.read();
}
}
void loop() {
signalMaster();
delay(1);
}
Как вы видите, дело в том, что я очень-очень быстро нажимаю на I2C, а петля получается очень тугой и быстрой. В этом суть упражнения, и отсюда вытекает проблема, которую необходимо решить.
Теперь время от времени я получаю случайную ошибку ввода-вывода с кодом raspi python. Этот код иногда дает сбой один раз, а затем все возвращается в нормальное русло, но время от времени он полностью ломается и никогда не восстанавливается.
Я подключил к нему логический анализатор и вот что обнаружил. D3 — контакт прерывания. Остальные шины I2C. В обычной транзакции я вижу, что все работает правильно (не обращайте внимания на другое содержание ответа, это был более ранний запуск)
и увеличьте основной запрос и ответ:
Однако когда у меня постоянный сбой, картина совсем другая
Увеличить:
Для меня это не имеет особого смысла. Зачем ему выполнять запись данных, и кто записывает 0x85FF... в мой буфер?
Спасибо
@Stefano Borini, 👍2
Обсуждение1 ответ
Используйте микросхему преобразования логического уровня.
источник изображения http://msx-elektronika.pl/en/logic-level-converter
Купил два, на выходных попробую, @Stefano Borini
@StefanoBorini, результаты?, @Juraj
Я добавил преобразователь логического уровня, но все равно получаю такие же ошибки. На данный момент я не уверен, в чем причина. Я решил, что на данный момент я просто использую традиционный микроконтроллер клавиатуры, но это определенно то, к чему я должен вернуться. Вечером добавлю фото своей установки, @Stefano Borini
@StefanoBorini, хорошо. Я собрал половину награды и два голоса, поэтому, если вы сейчас или в будущем захотите назначить награду за вопрос, напишите комментарий здесь, и я назначу награду в 50 баллов за этот вопрос (но только если я могу) т написать полезный ответ на него :-)), @Juraj
- Ошибка при компиляции: 'class TwoWire' has no member named 'setClock'
- Сбросить соединение I2C с arduino в качестве ведомого
- Преобразование float в байт, от Arduino до Raspberry Pi i2c
- Как изменить i2c-адрес Lidar Lite v3 с помощью библиотеки LidarLite (Решено)
- Ошибка в связи I2C Между Arduino и Raspberry Pi
- Arduino отключает шину i2c
- Как правильно отправлять байты между RPI и Arduino по I2C при использовании ISR без ошибок ввода-вывода?
- Отправка и получение различных типов данных через I2C в Arduino
Формат идеально подходит для реальной многобайтовой транзакции записи. Как будто библиотека Python вызывает
write_i2c_block_data
вместоread_i2c_block_data
. Это должно быть какая-то ошибка в конце Raspberry, возможно, в библиотеке py-smbus., @Majenkoсегодня вечером займусь отладкой., @Stefano Borini
@Majenko Хорошо, из краткой проверки текущего кода видно, что модуль smbus представляет собой прямой вызов i2c_smbus_access, который затем просто выполняет ioctl ... так что, если есть ошибка, это довольно глубоко. Любопытно, может ли быть фактором тот факт, что я использую 3,3 В вместо 5 В? Я читал противоречивые мнения о соединении arduino и raspi без переключателя уровня посередине., @Stefano Borini
Разница в напряжении не заставит Pi выполнять совершенно другую транзакцию., @Majenko
Это может быть полной чушью, но отключение прерываний на Arduino, а затем запуск raspi и включение прерываний переводит arduino в состояние, в котором он не может реагировать на (теперь это возможно) прерывания I2C/SMBus. Raspi действительно быстр по сравнению к arduino, и может быть состояние гонки. Я признаю; Я сам не верю в это решение, но если нет другого решения, стоит попробовать ;-). Как вы включаете/подтягиваете шину I2C. Резисторы могут быть слишком высокими. Ваши логические анализаторы не осци. Он показывает вам логические уровни, а не реальные напряжения. Т. тоже может быть проблемой., @Peter Paul Kiefer
@PeterPaulKiefer Я использую arduino mega 2560 с внутренними резисторами для шины i2c. У меня тоже есть osci, так что я могу дать ему чек. Я должен приостановить прерывания, так как я хочу быть уверен, что контакт прерывания не будет оставаться высоким в течение очень долгого времени, если арду выйдет из строя., @Stefano Borini
Если вы питаете шину I2C с помощью Arduino, вы используете 5 В (или это 3,3 В Arduino?). Это может разрушить ваш raspi, пожалуйста, будьте осторожны с этим. Это также проблема с PIN-кодом прерывания 5V, который слишком высок для raspi, он может терпеть это какое-то время, но это риск. Можно использовать делитель напряжения на два резистора., @Peter Paul Kiefer
Процедуры прерывания Arduino не должны выполняться в течение длительного времени. И, поскольку вы реагируете на нарастающий фронт вывода прерывания на raspi, это не проблема, если вывод прерывания имеет высокий уровень, если вы установили его в LOW перед следующим прерыванием. С другой стороны, прерывания необходимы для работы IC2. Вы можете потерять информацию, если прерывания не работают, когда raspi начал отправлять до включения прерываний., @Peter Paul Kiefer
@PeterPaulKiefer Отличные очки. Я собираюсь переделать несколько вещей завтра вечером и посмотреть, что произойдет. Что касается питания, то в настоящее время arduino питается от USB, а raspi — от блока питания. Так что да, технически они на разном напряжении. Однако идея состоит в том, что оба будут питаться от одного и того же источника питания 5 В. Конечно, логические уровни не будут меняться независимо от источника питания. Достаточно ли резистора делителя напряжения или мне следует использовать преобразователь логического уровня? в чем их физическая разница?, @Stefano Borini
5 В от источника питания регулируются до рабочего напряжения Raspi. Это не то же самое. Это 3,3В. См. ответ Бруно Броноски. https://raspberrypi.stackexchange.com/questions/3209/what-are-the-min-max-voltage-current-values-the-gpio-pins-can-handle., @Peter Paul Kiefer
Если ваш сигнал течет от более высокого напряжения к более низкому, резисторного делителя может быть достаточно. Если сигнал идет в обоих направлениях highV <--> lowV, вам нужен переключатель уровня. Если сигнал течет от более низкого к более высокому напряжению, а устройство с более высоким напряжением также интерпретирует высокий уровень устройства с более низким напряжением как высокий, вы можете соединить устройства напрямую друг с другом, если вы уверены, что более высокое напряжение устройство никогда не подавать питание на провод., @Peter Paul Kiefer
Какую малину вы используете? Это может быть проблема с растяжкой часов. У меня это тоже есть с проектом Arduino. Если ведомое устройство не может ответить, оно пытается растянуть тактовый сигнал. У Raspberry есть некоторые проблемы с этим, и как только часы синхронизации будут потеряны, оба устройства больше не будут работать ... Пока вы не сбросите линию i2c., @Adriano
@adriano я использую ноль пи, @Stefano Borini
Не уверен, но я думаю, что это также связано с ошибкой растяжения часов. Как только Arduino растянет часы, raspy потеряет синхронизацию с вашим Arduino., @Adriano