Разветвитель шины CAN

CAN (англ. Controller Area Network — сеть контроллеров) — стандарт промышленной сети, ла-ла-ла… бла-бла-бла…

Для моих применений (дома) нужно выделить основное: под CAN-сетью обычно подразумевается сеть топологии «шина» с физическим уровнем в виде дифференциальной пары, что, мягко говоря, усложняет монтаж если блоки автоматики находятся в разных уголках строения. Теоретически конечно можно проложить между устройствами единый кабель с небольшими ответвлениями, но практически это трудно реализуемо. Недаром почти умер 10BASE-2.

В связи с этим я задумался, как бы шинную топологию CAN превратить в «звезду» ? Первое решение, что называется, «в лоб». Взять микроконтроллер со встроенным CAN-интерфейсом и на SPI повесить еще один CAN. Получаем 2 разные сети. Микроконтроллер, получив пакет через hardware-CAN, шлет его в SPI-CAN. И наоборот. Так родилась вот такая маленькая прикольная штука:

Плата размером 50х32мм. Камень PIC18F46K80.

Собственно СAN1 подключен через передатчик MCP2551 напрямую в микроконтроллер:

CAN2 подключен через MCP2515 в SPI микроконтроллера:

С софтом не стал заморачиваться.

void main(){
    Prepare(); // подготовка камня к работе
    while(1) { // бесконечный цикл
        asm {CLRWDT}; // очищаем watchdog
        Msg_Rcvd = CANRead(&PACKET.id_full, // попытка приема из CAN Шины
                           &PACKET.data_bytes,
                           &PACKET.data_length,
                           &Can_Rcv_Flags);
        if (Msg_Rcvd) // если там что-то есть
            CANSPIWrite(PACKET.id_full, // пишем это в CANSPI
                        PACKET.data_bytes,
                        PACKET.data_length,
                        CanSpi_Send_Flags);

        Msg_Rcvd = CANSPIRead(&PACKET.id_full, // попытка приема из CANSPI
                              &PACKET.data_bytes,
                              &PACKET.data_length,
                              &CanSpi_Rcv_Flags);
        if (Msg_Rcvd) // если там что-то есть
            CANWrite(PACKET.id_full, // пишем это в CAN
                     PACKET.data_bytes,
                     PACKET.data_length,
                     Can_Send_Flags);
    }
}

Улучшать и расширять идею можно до бесконечности. Можно на SPI повесить несколько CAN-контроллеров и дергать их по очереди. Нам же нужно повторить пакет из одного сегмента во все остальные ? 🙂 Можно разгуляться по полной и взять PIC32MK0512GPE064. У него 4 CAN интерфейса и 6 SPI. Особо не мудрствуя, получим 10-и портовый свитч. Именно свитч а не хаб, т.к. принимает пакет полностью в одном сегменте и последовательно передает его же в другие сегменты. Такой подход хорош тем, что можно на уровне микроконтроллера инициализировать каждый канал на свою скорость, что собственно и делают китайцы, предлагая вот такую железку:

И даже пишут к ней софт для настройки. Маршрутизация, однако 🙂

Все вроде хорошо, но цена вопроса… 4 порта за 9700р это очень жестоко. (тут надо сказать что на али попадаются и 7 портов за ~9000р. типа дешевле) Не буду даже пытаться посчитать во сколько встанет озвездение шины CAN в реальном доме, но явно дороже Ethernet-а. Конечно покупать я это не собирался. Как идею использовать можно, но (как обычно) есть нюанс…

CAN используется в основном в системах жесткого реального времени и шина позволяет получить сумасшедшую скорость передачи мелких пакетов при минимальных задержках. Для Ethernet со скоростью передачи 100 МБит максимальное количество кадров в секунду составляет до 29000 кадров/с. 17241 кадров/с — предельная скорость CAN… при 1 МБит 🙂

Честно скажу, реальные задержки со своим двухканальным свитчем не измерял, но это точно не ноль. Скорости арбитража как на одном сегменте тут никак не достигнешь просто потому что перед трансляцией пакет принимается полностью, что нарушает синхронность работы can-сети. Особенно если таких «тройников» стоит несколько в ряд — задержки будут весьма большие. Это сложно для тех кто не знает о чем я вообще пишу и легко для тех кто знает что такое CAN. По-этому просто не буду вдаваться в подробности.

Я начал искать, неужели нельзя сделать именно синхронную побитовую работу разных сегментов? Оказывается можно. Основная проблема в том, что нельзя просто соединить can-передатчики друг с другом rx-tx и tx-rx. Вкратце суть в том, что передатчик во время передачи одновременно еще и слушает шину на предмет того, что он передал, и если он отпустил шину в «1» а другой передатчик в это время положил шину в «0» — первый проигрывает арбитраж и затыкается до освобождения линии, после чего повторяет попытку передачи. Тут посоветую почитать статью про повторитель CAN, который я в общем-то и сделал по-своему на high-speed логике.

На 2 канала получилась вот такая штука:

 

Из плюсов: мгновенная скорость, дешевизна. Из минусов: устал паять, 2 канала мало 🙂

А что если каскадировать эту схему на большее число каналов ? Так появился 8-и портовый хаб. Вот тут отлично видно что это звездная топология 🙂

И немедленно сделан в железе:

Джамперы на плате служат для отключения неиспользуемых каналов. Этот баг (или фича) обнаружился во время тестирования. Дело в том, что если к порту не подключено ни одного устройства — передатчик будет бесконечно пытаться отправить пакеты, принять которые просто некому.

Дальнейшее вылизывание схемы питания вместе с перерисовыванием платы в DipTrace привело к вот такой реализации хаба:

Самые внимательные заметят что стало на 4 микросхемы меньше. Розовеньким неразрывное питание 5в (без переходов). Синеньким земля, оранжевым выходы, ну и остальное по мелочи. Полигоны не показаны чтобы был виден масштаб бедствия.

Итого, ожидание:

И реальность:

 

Только после тестирования данный 8-и портовый хаб доступен в разделе «Купить» 🙂

Если вас заинтересовал повторитель CAN1<->(SPI)CAN2 на PIC18F46K80 из начала статьи — напишите или позвоните — их у меня тоже есть.

Спасибо что дочитали. Всем удачных разработок.

Об авторе demid

Однажды открыл для себя микроконтроллеры и с тех пор не отпускает...
Запись опубликована в рубрике Проекты. Добавьте в закладки постоянную ссылку.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

*

code