SPI: Master&Slaves. Источник картинки
Довольно часто при создании различных самоделок на основе микроконтроллера Arduino разработчики как бы «приделывают к телу руки и ноги», то есть присоединяют некую периферию, которая управляется с центрального микроконтроллера. Однако иногда возникают такие ситуации, когда необходимо соединить «два мозга друг с другом», то есть соединить два микроконтроллерa. Об этом мы и поговорим в этой статье.
Для коммуникации существует несколько вариантов, и один из них называется SPI.
SPI (англ. Serial Peripheral Interface, SPI bus — последовательный периферийный интерфейс, шина SPI) — последовательный синхронный стандарт передачи данных в режиме полного дуплекса, предназначенный для обеспечения простого и недорогого высокоскоростного сопряжения микроконтроллеров и периферии. SPI также иногда называют четырёхпроводным (англ. four-wire) интерфейсом.
Автор: Cburnett, Источник картинки
В отличие от стандартного последовательного порта (англ. standard serial port), SPI — это синхронный интерфейс, в котором любая передача синхронизирована с общим тактовым сигналом, генерируемым ведущим устройством (процессором). Принимающая (ведомая) периферия синхронизирует получение битовой последовательности с тактовым сигналом. К одному последовательному периферийному интерфейсу ведущего устройства-микросхемы может присоединяться несколько микросхем. Ведущее устройство выбирает ведомое для передачи, активируя сигнал «выбор кристалла» (англ. chip select) на ведомой микросхеме.
Периферия, которая не была выбрана процессором, не будет принимать участия в передаче по SPI.
Интерфейс
В SPI используются четыре цифровых сигнала:
- MOSI — выход ведущего, вход ведомого (англ. Master Out Slave In). Служит для передачи данных от ведущего устройства ведомому.
- MISO — вход ведущего, выход ведомого (англ. Master In Slave Out). Служит для передачи данных от ведомого устройства ведущему.
- SCLK или SCK — последовательный тактовый сигнал (англ. Serial Clock). Служит для передачи тактового сигнала для ведомых устройств.
- CS или SS — выбор микросхемы, выбор ведомого (англ. Chip Select, Slave Select).
Имена портов интерфейса SPI могут различаться в зависимости от производителя аппаратных средств, при этом возможны такие варианты:
- MISO: SOMI, SDO (на устройстве), DO, DON, SO, MRSR.
- MOSI: SIMO, SDI (на устройстве), DI, DIN, SI, MTST.
- SCLK: SCK, CLK, SPC (SPI serial port clock).
- SS: nCS, CS, CSB, CSN, NSS, nSS, STE, SYNC.
Синхронизация в SPI
Частота следования битовых интервалов в линиях передачи данных определяется синхросигналом SCK, который генерирует ведущее устройство, ведомые устройства используют синхросигнал для определения моментов изменения битов на линии данных, при этом ведомые устройства никак не могут влиять на частоту следования битовых интервалов.
Как в ведущем устройстве, так и в ведомом устройстве есть счётчик импульсов синхронизации (битов). Счётчик в ведомом устройстве позволяет последнему определить момент окончания передачи пакета. Счётчик сбрасывается при выключении подсистемы SPI, такая возможность всегда имеется в ведущем устройстве. В ведомом устройстве счётчик обычно сбрасывается деактивацией интерфейсного сигнала SS.
Так как действия ведущего и ведомого устройства тактируются одним и тем же сигналом, то к стабильности этого сигнала не предъявляется никаких специальных требований, за исключением ограничения на длительность полупериодов, которая определяется максимальной рабочей частотой более медленного устройства. Это позволяет использовать SPI в системах с низкостабильной тактовой частотой, а также облегчает программную эмуляцию ведущего устройства.
Приём и передача данных в SPI
Передача осуществляется пакетами. Длина пакета, как правило, составляет 1 байт (8 бит), при этом известны реализации SPI с иной длиной пакета, например, 4 бита. Ведущее устройство инициирует цикл связи установкой низкого уровня на выводе выбора подчинённого устройства (SS) того устройства, с которым необходимо установить соединение. При низком уровне сигнала SS:
- схемотехника ведомого устройства находится в активном состоянии,
- вывод MISO переводится в режим «выход»,
- тактовый сигнал SCLK от ведущего устройства воспринимается ведомым и вызывает считывание на входе MOSI значений, передаваемых от ведущего битов и сдвиг регистра ведомого устройства.
Автор: Cburnett, Источник картинки
Подлежащие передаче данные ведущее и ведомое устройства помещают в сдвиговые регистры. После этого ведущее устройство генерирует импульсы синхронизации на линии SCLK, что и приводит к взаимному обмену данными. Передача данных идёт бит за битом от ведущего по линии MOSI и от ведомого по линии MISO.
Передача осуществляется, начиная со старших битов, но некоторые производители допускают изменение порядка передачи битов программными методами. После передачи каждого пакета данных ведущее устройство, в целях синхронизации ведомого устройства, может перевести линию SS в высокое состояние.
Режимы работы интерфейса SPI
Возможны четыре режима синхронизации. Режим определяется комбинацией бит CPHA и CPOL:
- CPOL = 0 — исходное состояние сигнала синхронизации — низкий уровень.
- CPOL = 1 — исходное состояние сигнала синхронизации — высокий уровень.
- CPHA = 0 — выборка данных производится по переднему фронту (переключению) сигнала синхронизации. То есть по переключению из основного в противоположное ему.
- CPHA = 1 — выборка данных производится по заднему фронту (переключению) сигнала синхронизации.То есть по переключению обратно к основному из противоположного.
Для обозначения режимов работы интерфейса SPI принято следующее соглашение:
- режим 0 (CPOL = 0, CPHA = 0),
- режим 1 (CPOL = 0, CPHA = 1),
- режим 2 (CPOL = 1, CPHA = 0),
- режим 3 (CPOL = 1, CPHA = 1).
Топология систем связи на базе SPI
В простейшем случае к ведущему устройству подключено единственное ведомое устройство и необходим двусторонний обмен данными. В таком случае используется трёхпроводная схема подключения. Интерфейс SPI позволяет подключать к одному ведущему устройству несколько ведомых устройств, причём подключение может быть осуществлено несколькими способами.
Первый способ дает возможность реализовать радиальную структуру связи (топология типа «звезда»), его принято считать основным вариантом подключения нескольких ведомых устройств:
Автор: Cburnett, Источник картинки
В этом случае для обмена более чем с одним ведомым устройством, ведущее устройство должно формировать соответствующее количество сигналов выбора ведомого устройства (SS). При обмене данными с ведомым устройством, соответствующий ему сигнал SS переводится в активное (низкое) состояние, при этом все остальные сигналы SS находятся в неактивном (высоком) состоянии. Выводы данных MISO ведомых устройств соединены параллельно, при этом они находятся в неактивном состоянии, а перед началом обмена один из выходов (выбранного ведомого устройства) переходит в активный режим.
Второй способ позволяет выполнять структуру связи типа «кольцо»:
Автор: Cburnett, Источник картинки
В данном случае для активации одновременно нескольких ведомых устройств используется один сигнал SS, а выводы данных всех устройств соединены последовательно и образуют замкнутую цепь. При передаче пакета от ведущего устройства этот пакет получает первое ведомое устройство, которое, в свою очередь, транслирует свой пакет следующему ведомому устройству и так далее. Для того чтобы пакет от ведущего устройства достиг определённого ведомого устройства, ведущее устройство должно отправить ещё несколько пакетов.
Преимущества и недостатки интерфейса SPI
Преимущества
- Полнодуплексная передача данных по умолчанию.
- Более высокая пропускная способность по сравнению с I²C или SMBus.
- Возможность произвольного выбора длины пакета, длина пакета не ограничена восемью битами.
- Простота аппаратной реализации.
- Используется только четыре вывода, что гораздо меньше, чем для параллельных интерфейсов.
- Однонаправленный характер сигналов позволяет при необходимости легко организовать гальваническую развязку между ведущим и ведомыми устройствами.
- Максимальная тактовая частота ограничена только быстродействием устройств, участвующих в обмене данными.
Недостатки
- Необходимо больше выводов, чем для интерфейса I²C.
- Ведомое устройство не может управлять потоком данных.
- Нет подтверждения приёма данных со стороны ведомого устройства (ведущее устройство может передавать данные «в никуда»).
- Нет определённого стандартом протокола обнаружения ошибок.
- Отсутствие официального стандарта, что делает невозможным сертификацию устройств.
- По дальности передачи данных интерфейс SPI уступает таким стандартам, как UART и CAN.
- Наличие множества вариантов реализации интерфейса.
- Нет поддержки горячего подключения устройств.
А теперь если мы попробуем обратиться к микроконтроллеру Arduino и откроем одну из стандартных библиотек, идущих в комплекте для библиотеки SPI, под названием Digital Pot Control (управление цифровым потенциометром), то мы сможем с помощью неё организовать общение с подчинённым устройством в рамках этого интерфейса.
Скетч ниже предназначен для управления AD5206, многоканальным цифровым потенциометром. Устройство является достаточно интересным и служит для изменения сопротивления в цепи электронным способом, а не вручную. Если кому интересно, можете почитать подробные спецификации этого потенциометра здесь.
Одним из его применений может быть изменение яркости светодиодов за счёт плавной регулировки сопротивления.
Говоря о технических особенностях этого устройства, можно сказать, что этот цифровой потенциометр имеет возможность установки 256 позиций и является шестиканальным (то есть поддерживает 6 подключаемых устройств, например, светодиодов). Его возможности позволяют заменить механические потенциометры, номиналами 10, 50 или 100 кОм.
Каждый из 6 переменных резисторов потенциометра выведен на корпус микросхемы в виде 3 контактов, и логика подключения к ним ничем не отличается от подключения обычных переменных резисторов.
Назначение пинов на корпусе микросхемы можно посмотреть на рисунке ниже:
Источник картинки
Принципиальную схему соединений светодиодов с микросхемой и пинами Arduino Uno можно увидеть на рисунке ниже:
Источник картинки
Источник картинки
Код довольно простой, он реализует сказанное выше и работает следующим образом: плавно изменяется сопротивление на каждом из 6 каналов, пробегая по каждой из 256 позиций, заставляя светодиоды сначала плавно ярко «разгореться», а потом — также плавно погаснуть. Все требующиеся пояснения содержатся в комментариях к коду.
/*
Digital Pot Control
This example controls an Analog Devices AD5206 digital potentiometer.
The AD5206 has 6 potentiometer channels. Each channel's pins are labeled
A - connect this to voltage
W - this is the pot's wiper, which changes when you set it
B - connect this to ground.
The AD5206 is SPI-compatible,and to command it, you send two bytes,
one with the channel number (0 - 5) and one with the resistance value for the
channel (0 - 255).
The circuit:
* All A pins of AD5206 connected to +5V
* All B pins of AD5206 connected to ground
* An LED and a 220-ohm resisor in series connected from each W pin to ground
* CS - to digital pin 10 (SS pin)
* SDI - to digital pin 11 (MOSI pin)
* CLK - to digital pin 13 (SCK pin)
created 10 Aug 2010
by Tom Igoe
Thanks to Heather Dewey-Hagborg for the original tutorial, 2005
*/
// inslude the SPI library:
#include <SPI.h>
// set pin 10 as the chip select for the digital pot:
const int chipSelectPin = 10;
void setup() {
// set the chipSelectPin as an output:
pinMode(chipSelectPin, OUTPUT);
// initialize SPI:
SPI.begin();
}
void loop() {
// go through the six channels of the digital pot:
for (int channel = 0; channel < 6; channel++) {
// change the resistance on this channel from min to max:
for (int level = 0; level < 255; level++) {
digitalPotWrite(channel, level);
delay(10);
}
// wait a second at the top:
delay(100);
// change the resistance on this channel from max to min:
for (int level = 0; level < 255; level++) {
digitalPotWrite(channel, 255 - level);
delay(10);
}
}
}
void digitalPotWrite(int address, int value) {
// take the SS pin low to select the chip:
digitalWrite(chipSelectPin, LOW);
delay(100);
// send in the address and value via SPI:
SPI.transfer(address);
SPI.transfer(value);
delay(100);
// take the SS pin high to de-select the chip:
digitalWrite(chipSelectPin, HIGH);
}
Как мы уже упоминали в самом начале, интерфейс SPI позволяет не только управлять каким-то ещё одним устройством, но и осуществлять полноценную связь в рамках модели ведущий/ведомый между двумя и более ардуинами.
Код, приведённый ниже, работает следующим образом: ардуины связаны друг с другом через SPI. Каждая из них имеет подключённую кнопку-замыкатель. Если происходит нажатие кнопки на ведущем устройстве — включается белый диод на подчинённой ардуине. И, соответственно, если нажимается кнопка на ведомом устройстве, то загорается красный светодиод на ведущей ардуине. Сам пример взят здесь, можете почитать более подробно, если интересно. Все требующиеся пояснения содержатся в комментариях к коду.
Master Arduino Code:
//SPI MASTER (ARDUINO)
//SPI COMMUNICATION BETWEEN TWO ARDUINO
//CIRCUIT DIGEST
#include<SPI.h> //Library for SPI
#define LED 7
#define ipbutton 2
int buttonvalue;
int x;
void setup (void)
{
Serial.begin(115200); //Starts Serial Communication at Baud Rate 115200
pinMode(ipbutton,INPUT); //Sets pin 2 as input
pinMode(LED,OUTPUT); //Sets pin 7 as Output
SPI.begin(); //Begins the SPI commnuication
SPI.setClockDivider(SPI_CLOCK_DIV8); //Sets clock for SPI communication at 8 (16/8=2Mhz)
digitalWrite(SS,HIGH); // Setting SlaveSelect as HIGH (So master doesnt connnect with slave)
}
void loop(void)
{
byte Mastersend,Mastereceive;
buttonvalue = digitalRead(ipbutton); //Reads the status of the pin 2
if(buttonvalue == HIGH) //Logic for Setting x value (To be sent to slave) depending upon input from pin 2
{
x = 1;
}
else
{
x = 0;
}
digitalWrite(SS, LOW); //Starts communication with Slave connected to master
Mastersend = x;
Mastereceive=SPI.transfer(Mastersend); //Send the mastersend value to slave also receives value from slave
if(Mastereceive == 1) //Logic for setting the LED output depending upon value received from slave
{
digitalWrite(LED,HIGH); //Sets pin 7 HIGH
Serial.println("Master LED ON");
}
else
{
digitalWrite(LED,LOW); //Sets pin 7 LOW
Serial.println("Master LED OFF");
}
delay(1000);
}
Slave Arduino Code:
//SPI SLAVE (ARDUINO)
//SPI COMMUNICATION BETWEEN TWO ARDUINO
//CIRCUIT DIGEST
//Pramoth.T
#include<SPI.h>
#define LEDpin 7
#define buttonpin 2
volatile boolean received;
volatile byte Slavereceived,Slavesend;
int buttonvalue;
int x;
void setup()
{
Serial.begin(115200);
pinMode(buttonpin,INPUT); // Setting pin 2 as INPUT
pinMode(LEDpin,OUTPUT); // Setting pin 7 as OUTPUT
pinMode(MISO,OUTPUT); //Sets MISO as OUTPUT (Have to Send data to Master IN
SPCR |= _BV(SPE); //Turn on SPI in Slave Mode
received = false;
SPI.attachInterrupt(); //Interuupt ON is set for SPI commnucation
}
ISR (SPI_STC_vect) //Inerrrput routine function
{
Slavereceived = SPDR; // Value received from master if store in variable slavereceived
received = true; //Sets received as True
}
void loop()
{ if(received) //Logic to SET LED ON OR OFF depending upon the value recerived from master
{
if (Slavereceived==1)
{
digitalWrite(LEDpin,HIGH); //Sets pin 7 as HIGH LED ON
Serial.println("Slave LED ON");
}else
{
digitalWrite(LEDpin,LOW); //Sets pin 7 as LOW LED OFF
Serial.println("Slave LED OFF");
}
buttonvalue = digitalRead(buttonpin); // Reads the status of the pin 2
if (buttonvalue == HIGH) //Logic to set the value of x to send to master
{
x=1;
}else
{
x=0;
}
Slavesend=x;
SPDR = Slavesend; //Sends the x value to master via SPDR
delay(1000);
}
}
Результат работы кода:
Из интересных моментов в этом примере, на мой взгляд, можно выделить, что используется делитель частоты синхронизации SPI. В данном случае используется делитель на 8, то есть связь между ардуинами осуществляется на скорости в 2 МГц (однако значение по умолчанию обычно равно SPI_CLOCK_DIV4, одна четверть от частоты контроллера).
Всего возможны 7 вариантов делителей частоты:
- SPI_CLOCK_DIV2
- SPI_CLOCK_DIV4
- SPI_CLOCK_DIV8
- SPI_CLOCK_DIV16
- SPI_CLOCK_DIV32
- SPI_CLOCK_DIV64
- SPI_CLOCK_DIV128
Однако один из самых красивых примеров, который, на мой взгляд, хорошо иллюстрирует взаимодействие между собой множества ардуин, показан всё-таки ниже.
Электронная начинка:
Источник картинки
Результат сборки:
В этой самоделке используется взаимодействие мастера и множества слейвов, которые работают синхронно и образуют вращающимися стрелками текущее время. Кому интересно более подробно почитать о проекте, может это сделать здесь.
Правда следует оговориться, что здесь для взаимодействия использован более продвинутый способ, где применяется интерфейс I2C, который тратит в 2 раза меньшее количество линий (2 против 4 у SPI). Хотя теоретически эта самоделка вполне могла быть выполнена и с использованием протокола SPI, однако тогда бы количество соединений критически выросло (видимо, именно поэтому автором и был выбран другой, более лаконичный на количество выводов способ).
С кодом этой реализации можно ознакомиться здесь.
Подытоживая, хочу сказать, что возможности протокола SPI не ограничиваются только перечисленными выше примерами. Однако если попытаться обобщить, то основными его назначениями, на мой взгляд, являются возможность расширить количество доступных контактов в рамках самоделок, а также разгрузить используемые микроконтроллеры, «сбрасывая» выполняющуюся задачу на подчинённых.
НЛО прилетело и оставило здесь промокод для читателей нашего блога:
— 15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.
Комментарии (26)
gleb_l
27.04.2022 11:58+1Обмен по SPI - фактически DMA в мире микроконтроллеров. Сравнивать его с I2C и тем более с RS-232 некорректно - область первого - внутрисистемный высокоскоростной синхронный обмен с заранее известным количеством hardwire-адресуемых устройств. В принципе, SPI реализуется аппаратно парой сдвиговых регистров и парой регистров-защелок без всяких МК, поэтому, особой стандартизации и не требует - многие системы, между компонентам которых еще во времена ИС малой степени интеграции не хотелось тянуть параллельные шлейфы, как г-н Журден, говорили прозой - то есть использовали последовательный синхронный обмен, который еще не был назван SPI :)
I2C же - адресный протокол внутрисистемного и ближнего межсистемного обмена, и соответственно, нагружен метаинформацией, что требует дополнительной буферизации при обмене с абсолютно детерминированным таймингом (например ЦАП/АЦП). Хотя сейчас буферизация на кристалле - совершенно не проблема для ИС, а ограничение на количество выводов - как раз проблема, увеличивающая стоимость - поэтому I2C популярен и для синхронных по своей природе устройств :)
mctMaks
27.04.2022 12:02самоделка, представленная в конце весьма интересная. По видео не сразу понял, что там два шаговых мотора стрелки вращают, почему-то думал что сервы будут.
sami777
27.04.2022 12:09Разве SPI синхронный протокол? Работа передатчика никак не синхронизируется с работой приемника. Наоборот то да. Но передатчик ни когда не узнает, что там с приемником.
atd
27.04.2022 13:06+1Он "синхронный" в том плане, что известно когда надо сэмплить линию данных (как и в I²C), в отличие от асинхронного UART.
AKudinov
27.04.2022 13:09+1Конечно, SPI синхронный протокол. У него есть выделенная, по которой тактовый сигнал синхронизации передачи данных ходит.
И, если ведомый спроектирован нормально, то ведущий может в любой момент прочитать из ведомого слово состояния и узнать, что с ним происходит.
sim2q
27.04.2022 13:19Может подскажет кто почти по теме...
Есть устройство где два блока (морда с крутилками/мигалками и SoC) связаны по SPI четырьмя линиями как здесь. Задача - эмулировать морду. Но осложняется, что посылки могут быть как 4 ,8 и на вскидку до 24 бит. Также летают какие то по видимому служебные сигналы ид... (смотрю в PulseView)
Каким бы статистическим анализатором воспользоваться что бы найти повторяющиеся паттерны? Уж очень не хочется вручную.пример
iiiytn1k
27.04.2022 15:07Там точно SPI-шина? То, что изображено на картинке на неё не похоже.
sim2q
27.04.2022 19:41То что последовательное - точно (видно что тактируется по фронту), но то что именно SPI как в статье - не совсем. Сигналы называются ACK, TX, RX, STB.
Мечтается просто взять и насэмплировать по много раз одних и тех же операций, скормить какому то софту и посмотреть какие паттерны и где.
Polaris99
27.04.2022 14:00Копия статьи из Википедии плюс пара строк на Ардуино - новый стандарт писательства на Хабре?
juramehanik
27.04.2022 18:38Ну дак это
канал об анимэсайт для программистов от программистов.
Статья про основы петончика с инфой взятой из соседнего поискового запроса очевидно получила бы тут сразу тонну минусов. А по не программистким (но техническим) темам тут чуть более снисходительнее.
AlexanderS
27.04.2022 20:44+1Соединение типа «кольцо» больше теоретическое, никогда на практике не встречал такое соединение — обычно несколько микросхем подключают или напрямую, если с пинами проблем нет, или «звездой».
YDR
28.04.2022 11:36да, я как-то тоже не уверен, возможно ли такое последовательное соединение (если не сделать специально). Вот JTAG да, можно цепочкой соединять, объединяя TCK.
AlexanderS
28.04.2022 12:06Да потому что выгоды нет никакой — количество пинов то же самое. А как конкретный производитель там у себя трансляцию реализовал или не реализовал неизвестно. Часть микросхем вообще MISO не подразумевает. Получается надо штудировать даташиты + программная нагрузка возрастает. Ну и кому это надо, если можно просто четыре сигнала подключить не думая)
Gryphon88
28.04.2022 13:34Удобная штука, если есть много однотипных датчиков, которые можно опрашивать одновременно, а с ногами недостача.
AlexanderS
28.04.2022 20:33+1Но на датчик же всё равно обычно нужно команду на чтение отправить. SS у всех опущены будут. Это команда спровоцирует ответ от первого датчика, который вторым будет как команда приниматься? А первичная команда как до второго дойдёт? Или она из первого датчика потом за ответом выйдет и второй датчик не примет данные от первого, но среагирует на команду, а за это же время на первый датчик придёт нулевой байт, который далее ни на что не повлияет? Как-то замороченно… Если проверить такую логику не на чем, лучше уж не рисковать и дешифратор поставить)
Gryphon88
29.04.2022 12:51Пропустил важный момент: датчики подключены к сдвиговым регистрам, или чисто входным, или к паре 595(отправка команды)+165(прием ответа). Тогда все нормально: подали SS, ноги регистров ушли в high-z, в mosi запихали команду, из miso "выдавился" результат измерения.
Bombesko
Добрый день, спасибо за статью! А не подскажите как соединить 2 ведущих/1 ведомый? Т.е. две ардуинки которые собирают данные и отдают главной, а та отсылает по интернету куда надо.. Я понимаю что с каждой можно собрать и сразу отправить, но там такой кейс :)
GennPen
Нужно ставить коммутатор линий. Иначе при одновременной работе двух ведущих устройств будут коллизии.
Но правильней поменять ведущих и ведомых местами.
nerudo
Для этих целей лучше использовать I2C — там есть встроенный мультимастеринг. Правда его часто забывают реализовать ;)
0xED
Предложу такие варианты:
Соединить одним проводом двух мастеров, и пусть один поднимает на нем уровень в момент когда не опрашивает слейва, тогда второй может в этот момент общаться.
Модифицированный первый вариант - CS от первого мастера параллельно подключен как вход второго мастера, и второй следит, когда первый перестанет опрашивать слейва.
Если мастеры запрашивают одно и то же, то можно второй мастер сконфигурировать как "Receive only master", и он будет подслушивать, что отвечает слейв на запросы первого.
Ivanii
Поменять мастер/слейв местами и далее по классике.
nixtonixto
SPI у большинства контроллеров, от AVR до STM32 поддерживает режим Мультимастер. Когда все другие Мастеры автоматически переходят в Слэйв, увидев, что один из Мастеров опустил уровень на CS. Дальнейшая обработка, прослушивание MOSI и пр. производится программно, но работает вполне надёжно. Для Ардуино этого может не быть, но на С делал для AVR и работало прекрасно.
VT100