3.26. Шина CAN у коді¶
machine.CAN обгортає апаратний контролер CAN. Ініціалізуйте його з ідентифікатором шини та швидкістю передачі бітів:
from machine import CAN
can = CAN(1, 500_000)
can.set_filters(None) # accept all incoming IDs
Швидкість передачі бітів повинна точно збігатися з усіма іншими вузлами на шині – 125_000, 250_000, 500_000 та 1_000_000 є загальноприйнятими значеннями. set_filters() налаштовує, які ідентифікатори контролер пропускатиме; None означає приймати все (корисно під час налагодження зв’язку, менш корисно, коли шина зайнята).
3.26.1. Всередині контролера¶
Між Python-кодом камери та шиною знаходяться три апаратні компоненти – поштові скриньки TX, фільтр приймача та FIFO RX. Кожен з них відповідає певній частині API CAN, що використовується нижче.
Поштові скриньки TX контролера, фільтр приймача та FIFO RX між програмним забезпеченням та шиною.¶
Поштові скриньки TX. Невеликий набір апаратних слотів (зазвичай три), що зберігають вихідні кадри, які камера передала через
send(), але які ще не досягли шини. Коли шина вільна, контролер вибирає поштову скриньку з ідентифікатором найменшого номера (найвищий пріоритет) та проводить арбітраж за шину від її імені. Камера не вибирає поштову скриньку; контролер призначає її та повертає її індекс зsend().Фільтр приймача. Конфігуроване апаратне забезпечення, що порівнює ідентифікатор кожного вхідного кадру зі списком шаблонів і відкидає все, що не збігається. Кадри, що пройшли, продовжують шлях до FIFO RX; відхилені кадри відкидаються контролером, не досягаючи Python.
set_filters()налаштовує ці шаблони.FIFO RX. Черга першим увійшов, першим вийшов – перший кадр, що увійшов, є також першим, що виходить, як черга у касу. Контролер додає прийняті кадри в кінець черги в міру їх надходження, а
recv()знімає їх з початку в тому самому порядку. Черга важлива, оскільки шина приймає кадри у фоновому режимі, поки Python зайнятий іншим; камера потім спорожняє їх по одному без втрат, якщо FIFO не переповнений.
3.26.2. Надсилання кадру¶
send() ставить кадр у чергу для передачі:
can.send(0x123, b"\x01\x02\x03\x04")
Перший аргумент – це ідентифікатор (11-бітне ціле число для стандартного кадру); другий – корисне навантаження (від 0 до 8 байт для CAN Classic). Виклик повертає невелике ціле число – індекс, що ідентифікує апаратну поштову скриньку, до якої потрапив кадр. Контролер проводить арбітраж з іншими передавачами на шині та повторює передачу за необхідності без додаткової допомоги з боку програмного забезпечення.
Для розширених (29-бітних) ідентифікаторів виконайте АБО з прапорцем CAN.FLAG_EXT_ID у третьому аргументі:
can.send(0x18FF1234, b"hello", CAN.FLAG_EXT_ID)
3.26.3. Отримання кадрів¶
Контролер запускається без встановленого фільтра та відкидає кожен вхідний кадр. Перш ніж recv() поверне що-небудь, викличте set_filters() один раз – найпростіша форма – None, яка приймає кожен ідентифікатор:
can.set_filters(None) # accept every frame
recv() потім повертає наступний кадр у черзі отримання, або None, якщо нічого не очікує:
msg = can.recv()
if msg is not None:
can_id, data, flags, errs = msg
print("got", hex(can_id), bytes(data))
Шина заповнює FIFO RX у фоновому режимі, тому головний цикл просто спорожняє його з такою швидкістю, з якою він ітерується. Доки FIFO глибший за найдовший проміжок між спорожненнями, жодні кадри не втрачаються.
3.26.4. Фільтри¶
На реальній шині зазвичай багато кадрів, які камера не обробляє. Апаратні фільтри дозволяють контролеру відкидати непотрібні ідентифікатори до того, як вони досягнуть FIFO. set_filters() приймає список кортежів (id, mask, flags); кадр проходить фільтр, якщо його ідентифікатор, маскований значенням mask, збігається з налаштованим id:
# Accept only IDs 0x100 - 0x10F (mask off the bottom 4 bits)
can.set_filters(((0x100, 0x7F0, 0),))
# Accept IDs 0x300 and 0x700 exactly
can.set_filters(((0x300, 0x7FF, 0),
(0x700, 0x7FF, 0)))
Кадри, що не збіглися, відкидаються контролером і ніколи не з’являються у recv(), що економить як буферний простір, так і час процесора.
3.26.5. Стани помилок та відновлення¶
Реальна шина CAN стикається з помилками передачі – коротким замиканням на землю, відсутніми вузлами, електричними завадами, що спотворюють біти. Контролер веде два лічильники, що відстежують цю поведінку: лічильник помилок передачі (TEC) та лічильник помилок отримання (REC), кожен з яких збільшується при виявленні помилки та зменшується після успішної передачі. Значення лічильників переводять контролер в один з чотирьох станів:
Error Active (TEC та REC обидва нижче 96). Нормальна робота. Коли вузол виявляє помилку шини, він передає домінантний активний кадр помилки, що змушує всі інші вузли відкинути поточний кадр, щоб відправник міг повторити спробу.
Error Warning (будь-який лічильник досягає 96). Вузол залишається повністю активним на шині – стан попередження є програмним сигналом про накопичення помилок, а не зміною поведінки.
Error Passive (будь-який лічильник досягає 128). Вузол залишається на шині, але припиняє надсилати домінантні кадри помилок; помилки тепер сигналізуються пасивними (рецесивними) кадрами помилок, щоб несправний вузол не міг постійно руйнувати шину для всіх інших.
Bus Off (TEC досягає 256). Контролер вирішив, що цей вузол занадто ненадійний для участі. Він відключається від шини, припиняє передавати та підтверджувати, і залишається відключеним до тих пір, поки програмне забезпечення явно не перезапустить його.
Перші три переходи є повністю автоматичними – коли лічильники зменшуються після успішних кадрів, контролер самостійно повертається до стану Error Active без втручання.
Bus Off – єдиний стан, що вимагає дій з боку програмного забезпечення. restart() скидає контролер і повертає його до стану Error Active. Типовий шаблон – перевіряти стан у головному циклі та перезапускати після короткої затримки, щоб дати шині час стабілізуватись:
import time
from machine import CAN
can = CAN(1, 500_000)
can.set_filters(None)
while True:
if can.state() == CAN.STATE_BUS_OFF:
time.sleep_ms(100)
can.restart()
# ... rest of the loop
Поточні значення лічильників доступні через get_counters() для діагностики – TEC, що неухильно зростає на інакше тихій шині, зазвичай вказує на проблеми з проводкою, термінацією або неправильно налаштованою швидкістю передачі бітів.