Время говорить с камнями или USART Multi-processor Communication Mode

AVR
В устройствах, которые чуть сложнее «помигать на демоплате» часто встает вопрос коммуникации между блоками. Какие у нас есть варианты организации шины «один мастер-куча слейвов»?
1. SPI — классика жанра. Минус — надо к каждому слейву тянуть линию SS — Slave Select, чтобы выбирать конкретного
2. I2C (TWI) — вроде все хорошо, правда развязать двунаправленную шину — гемор тот еще.
3. ну и герой нашего обзора — USART Multi-processor Communication Mode

Работает на камнях, где есть полноценный USART (это меги). За базовый камень возьмем atmega32a.



В чем секрет режима? При передаче байта один из незначащих бит становится признаком того, адрес это или данные. В режиме передачи с длиной пакета 5-8 бит — это первый стопбит, в режиме 9-битного — это девятый бит. Рекомендуется использовать 9-битный пакет, с ним меньше всего геморроя. После получения байта с адресом, выполняется проверка адреса, и если это не наш пакет — то все остальное до следующего пакета с адресом — игнорируется. Причем игнорируется аппаратно — прерывания не возникает, данные тихо дропаются.

Нет лишней нагрузки на процессор, возможна организация дуплексного режима.

Как организовано физически:
В регистре UCSRA есть бит с названием MPCM. Когда этот бит установлен, проходят только адреса. Иначе — обычный режим работы.

Порядок работы такой:
1. Все слейвы выставляют бит MPCM в 1.
2. Читаем адрес. Адрес приходит как обычный байт, только в девятом бите — 1. Проверяем адрес. Если это наш адрес, то сбрасываем бит MPCM и ждем потока данных. Остальные слейвы бит не сбрасывают, соответственно весь поток данных пройдет мимо.
3. После окончания получения данных, текущий слейв выставляет бит обратно и ждет следующего адреса.

Есть возможность организовывать широковещательную рассылку (выделить, например, адрес 0 или 255), разбить на группы приема и прочие игрища с адресами — первая проверка-то делается программно.

Мастеру для того, чтобы указать значение девятого бита, перед отправкой байта надо установить (или сбросить) бит TXB8 в регистре UCSRB.

Соответственно, девятый бит читается из того же регистра из бита RXB8.

Комментарии (38)

RSS свернуть / развернуть
Работает на камнях, где есть полноценный USART (это меги)
Как минимум еще тини2313… а может и другие…
0
А я завтра напишу про запись во флеш память. Бутлоадеры всякие и иже с ними. Тоже из серии AVR-джедай :)
0
I2C (TWI) — вроде все хорошо, правда развязать двунаправленную шину — гемор тот еще
… ну у USART проводков не меньше
… а вообще USART-ом (имхо) легче управлять, а если еще и RS485 или RF — то и на больших растояниях, и более помехо-устойчивее
0
дело не в проводках, а в том, что, например, двунаправленная опторазвязка — достаточно нетривиальная вещь.
0
Если SPi-slave устройство поддерживает Daisy Chain режим то ничего никуда тянуть не надо, а тока данных поболе загонять, и так же поболе получать.
0
Спасибо, очень ценная и очень своевременная информация!
0
А где пример работы? Схема? Автор, поведай о джедайских битвах с граблями. Даташиты мы и сами умеем читать.
+2
Как показывает суровая наука статистика — не все :)
+1
искренне не понимаю необходимость этого битика, если тоже самое можно сделать и без него. отправил адрес, длинну передачи, сами байтики и црц для проверки и все пучком. объясните пожалуйста преимущества этой штуки.
0
  • avatar
  • 21h
  • 27 сентября 2011, 20:06
Битик позволяет аппаратно игнорировать чужие байтики, не падая почем зря в прерывание. Во времена 8051, когда этот MPCM появился (если не раньше) это было довольно актуально, т.к. камушки имели машинный цикл аж в 12 тактов и не так чтоб очень высокую тактовую.
0
  • avatar
  • Vga
  • 27 сентября 2011, 20:10
чтобы не попадать в прерывание адрес должен записываться в какой-нибудь регистр. а тут и так, и так будет прерывание, чтобы проверить прилетел ли это адрес или бит данных
0
  • avatar
  • 21h
  • 27 сентября 2011, 20:35
кажется вкурил. при поднятии флажка mpcm байты данных приниматься перестают. только байты с адресами. если адрес нужный приходит, то флажок этот нужно снять и начать прием данных.
0
  • avatar
  • 21h
  • 27 сентября 2011, 20:45
Вот именно. UART аппаратно проверяет девятый бит, если он установлен — байт принимается, иначе по тихому отправляется фтопку. Таким образом, принимаются только посылки с адресами до тех пор, пока ты не сбросишь флажок MPCM, обнаружив что очередной адрес — твой.
0
  • avatar
  • Vga
  • 27 сентября 2011, 21:41
жаль пока не понятно как с компьютера отправить такой адресный байтик. там такого управления нету.
0
  • avatar
  • 21h
  • 27 сентября 2011, 23:24
Гм, хз, держит ли винда 9-битный режим если настраивать порт через API. Впрочем, если не ошибаюсь, в качестве оного бита можно использовать parity-бит.
0
  • avatar
  • Vga
  • 27 сентября 2011, 23:53
геморрой знатный. я лучше соберу сегодня макеточку со второй мегой и попробую.
0
  • avatar
  • 21h
  • 28 сентября 2011, 09:58
Не так давно объединял в сеть по 485 штук 12 МК. Тоже коллега настаивала на этом 9-ом бите. Но так как прошивку и протокол взаимодействия пришлось писать самому решил, что я как-то переживу то что МК почем зря будет падать в прерывание. Если общаться между собой будут только МК вполне пригодное решение, но если в эту сеть запускать компутер (особенно с терминалом) то все становится менее радужным.
0
а 9ти битный режим приёма передачи должн быть постоянно включен?
или UCSZ2 можо отключить после приёма адресного пакета?
0
и поясните про аппаратную проверку. ведь всё равно адрес проверяется в прерывании
например(Си):
// обработчик приёмника UART
ISR(USART_RXC_vect)
{

if(UCSRA & (1<<MPCM)) // если включён мультипроцессорный режим
{
if ( UCSRB & (1<<RXB8) && UDR==UartAdr ) // если есть девятый бит
{
DisMultUart(); // то проверку отключаем
}
else
{
UCSRA &= ~ (1<<RXC);
UCSRB &= ~ (1<<RXB8);
return;
}
}
else //если мультипроц отключён то просто принимаем байты
{
InBufferRx(UDR); //положили в буфер
SetTask(Terminal); //вызвали обработчик
}
}
0
а 9ти битный режим приёма передачи должн быть постоянно включен?
Да
и поясните про аппаратную проверку. ведь всё равно адрес проверяется в прерывании
Адрес — да. А вот данные, адресованные другому получателю, игнорятся аппаратно.

Код ты привел какой-то странный… Зачем самому проверять девятый бит, в частности?
0
тогда проверять if ( UDR== 0х180 ) ???
0
Вся фишка multi-processor communication mode в том, что девятый бит проверяется аппаратно и все байтики, где он не установлен — аппаратно игнорируются. Таким образом, адреса отсылаются с установленным девятым битом, их принимают все процессоры в системе и проверяют адрес на соответствие своему. Тот процессор, который обнаружил свой адрес переходит в режим обычного приема и ловит все последущие байтики данных, тогда как остальные остаются в режиме ожидания своего адреса и байты данных (в которых девятый бит не установлен) аппаратно игнорируют.
А вообще чуть выше я разжевывал 21h то же самое.
0
Код ты привел какой-то странный… Зачем самому проверять девятый бит, в частности?
Проверять 9 бит — надо, чтобы отличить адрес от данных.

Например, опознали свой адрес. Пошли даннык. Принимаете их. А как узнать, кончились уже ваши данные или нет?
А очень просто. Проверяете 9 бит при приеме данных. Если пришел адресный байт — проверяете, ваш ли это адрес, нет — прекращаете прием, разрешив опять проверять 9 бит аппаратно.

Это упрощает и делает более понятным обработчик прерывания приема, иначе вам пришлось бы каким — то образом определять конец ваших данных, и городить ради этого гораздо больше.

Например, передавать в пакете число байт, а на приеме их считать, или вводить жесткую длину пакета, или еще чего…

А так — на каждый принятый в прерывании байт, делаете проверку его на адресный, если адрес — проверяете на совпадение, совпал — выключаете проверку 9 бита, не совпал — включаете… Не адресный — ставите флаг наличия принятого байта (считать можно и в главном цикле).

Просто и удобно.
0
Можно и так. Но, насколько я понял, в этом куске кода просто дублируется функциональность, уже имеющаяся в железе. Ну и все зависит от протокола и его реализации, в определенных случаях может быть удобнее определять конец передачи другим способом.
0
я так понял между всеми камнями два провода Rx/Tx. а как быть с передачей данных от слейва к мастеру? как узнает слейв что ему можно передавать в данный момент?
0
По запросу на передачу от мастера. Как и во всех подобных шинах — USB, I2C, etc. Хотя, здесь никаких проблем с передачей от слейва нет — есть же отдельная линия от слейва к мастеру. Нужно только чтобы два слейва не начинали передачу в один момент времени. Для этого есть адресация — в каждый момент активен только выбранный мастером слейв.
0
Автору — спасибо за подсказку! Ломал голову над нужным обменом, но толку было мало… А тут подвернулось — собрал — заработало так как надо! Один мастер -> куча слейвов, физ. линия RS485. Пашет. Слейвы работают с размером посылки 9 бит. Если ставить 8 — не распознает адрес.
0
Интересуєт похожая тема, но нужно слить данние из двух девайсов которые работают по ЮАРТу, отправить их по ЮАРТ-модему на устройство управления, а там отфильтровать и розеденить сигналы снова на два ЮАРТа.
Как такое забацать?
ТЫЦ на форум
0
А какое макс. количество слейвов можно подключить к master контроллеру???
0
  • avatar
  • Nemo
  • 19 августа 2014, 15:08
Зависит от протокола и нагрузочной способности ножек. С дополнительными мерами вроде буферов — только от протокола.
0
тоесть 2^8 девайсов (с буферами)?
0
Зависит от протокола. Делай 32-битные адреса и ставь 4*10^9 девайсов)
0
обычный уарт, как в статье, мастер stm32f407, слейвы atmega8. Слейвов будет не больше 64 штуки, так как растояния между платами не большие (максимум 50см), не буду использовать RS485 (диф. лини). между мастером и слейв будет опторазвязка.
0
Нужно ставить буфер на каждом слейве, или достаточно только на мастере???

0
Понятия не имею, от твоей задачи зависит, а я ее не знаю.
0
  • avatar
  • Vga
  • 09 сентября 2014, 04:39
Задача такая: 1 мастер (SMT32F407) и до 32 слейва (ATmega44). Мастер будет передавать инфу слейвам, и от них получать информацию. пакет не больше 8 байт.
0
Нужно управлять 9 битом в пакете, использую STM32F407, USART1:


USART_InitTypeDef USART_InitStructure;

	USART_InitStructure.USART_BaudRate = 115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_9b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

	USART_Init(USART1, &USART_InitStructure);
	USART_Cmd(USART1, ENABLE);


настроил использование 9 бита

USART_InitStructure.USART_WordLength = USART_WordLength_9b;


Питался делать так

USART_SendData(USART1, 0x100); //0x100 — 0000 0001 0000 0000

но на осцилографе у меня нули, тоесть 9 бит игнорируеться. Как можно установить?

0
  • avatar
  • Nemo
  • 06 ноября 2014, 12:54
ошибся, всё работает.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.