Перейти к основному содержимому

Работа со Spacewire

Каналы SpaceWire в составе микросхем серии «Мультикор» имеют ряд особенностей по сравнению с другими периферийными портами. По этой причине описание работы с ними вынесено в отдельный документ. Основная информация по каналам SpaceWire и их реализации в конкретной микросхеме содержится, соответственно, в стандарте интерфейса SpaceWire (и протокола RMAP), а также в руководстве пользователя на рассматриваемую микросхему. Здесь же рассмотрены основные моменты, необходимые для понимания принципов работы с каналами SpaceWire в составе микросхем серии «Мультикор».

Структура и основные принципы работы контроллера Spacewire

Рисунок 1. Структурная схема контроллера одного канала SpaceWire в микросхеме 1892ВМ12Т

Как видно из рисунка, контроллер SpaceWire состоит из нескольких основных блоков: Блоки Link Interface и LVDS реализуют непосредственно порт SpaceWire, задача которого – переправлять данные между внутренними FIFO микросхемы и линиями канала SpaceWire.

Блоки TX_BUFFER и RX_BUFFER – содержат в своем составе FIFO приема и передачи соответственно. Причем в каждом из направлений есть FIFO данных и FIFO дескрипторов. Этот момент будет рассмотрен далее, а пока можно принять эту информацию к сведению. Блок DMA осуществляет связь буферов с памятью, где хранятся передаваемые данные (или сохраняются принятые).

Здесь следует оговориться, что DMA – это единственный путь передать данные из памяти в канал SpaceWire или обратно. В этом одно из отличий SpaceWire от других периферийных интерфейсов в составе процессоров «Мультикор», где существует возможность программного доступа к буферу устройства без участия DMA.

Блок управления содержит в себе управляющие и статусные регистры, соответственно задающие режим работы блока и содержащие информацию о состоянии всех остальных блоков.

Перечень возможных коллизий при работе по SpaceWire

Невозможность установить соединение из-за заполненного приемного FIFO данных

Если у порта SpaceWire целиком заполнено приемное FIFO данных, то этот порт не сможет установить соединение, пока в приемном FIFO данных не освободится хотя бы одна ячейка. Данная ситуация может возникнуть при разрыве соединения во время передачи данных. Чтобы избежать данной ситуации, необходимо очищать приемное FIFO данных перед установкой соединения.

"Лишние" данные в FIFO данных приемника

Если перед установкой соединения в FIFO данных приемника были какие-то данные, то их невозможно отличить от данных, полученных после установки соединения. Это значит, что при приеме они добавятся в начало пакета, принимаемого от передатчика.

Чтобы избежать данной ситуации, необходимо очищать приемное FIFO данных перед установкой соединения.

"Лишние" данные в FIFO дескрипторов приемника

Если перед установкой соединения в FIFO дескриптора приемника были какие-то дескрипторы, то их невозможно отличить от дескрипторов, сформированных после установки соединения и получения новых пакетов от передатчика. При этом, если в FIFO данных приемника не было данных соответствующих пакетов (это могло быть, если DMA дескрипторов было остановлено, а DMA данных работало) - невозможно будет установить соответствие дескрипторов принятых данным.

Чтобы избежать данной ситуации, необходимо очищать приемное FIFO дескрипторов перед установкой соединения.

"Лишние" данные в FIFO данных передатчика

Если разрыв соединения произошел при передаче пакета, остаток пакета принимается в передающее FIFO данных по DMA, но не отправляется в канал, а просто игнорируется. Проблема возникает, если DMA данных передает больше данных, чем осталось в передаваемом пакете. Оставшиеся данных будут записаны в FIFO передатчика и не будут отправлены в канал до восстановления соединения и получения нового дескриптора. При этом отсутствуют механизмы, позволяющие понять, какие данные находятся в FIFO после завершения DMA-обменов.

Чтобы избежать данной ситуации, необходимо очищать передающее FIFO данных перед установкой соединения.

"Лишние" дескрипторы в FIFO дескрипторов передатчика

Если разрыв соединения произошел, когда в передающем FIFO дескрипторов остался один или несколько необработанных дескрипторов, то они никуда не денутся. Они останутся в этих FIFO, и поступят в контроллер. Который, в свою очередь, отработает эти дескрипторы, сформировав заданные пакеты из данных, присланных через DMA данных. При этом отсутствуют механизмы, позволяющие понять, какие из переданных дескрипторов отработаны, а какие - еще только в FIFO.

Чтобы избежать данной ситуации, необходимо очищать передающее FIFO дескрипторов перед установкой соединения.

Отсылка случайных данных в канал SpaceWire

Применимо к микросхемам 1892ВМ8Я, 1892ХД1Я, 1892КП1Я.

Порты SpaceWire данных микросхем могут отсылать случайные данные при установке соединения, изменении скорости передачи или при разрыве соединения. В канал отсылается один-два символа при каждом действии (установили соединение - в канал отправилось не более двух символов, далее ничего не будет непроизвольно отсылаться до изменения скорости передачи или разрыва соединения). Отсылка происходит спорадически, невозможно предсказать, произойдет ли это в конкретном случае.

Удаленный абонент должен учитывать эту вероятность при обработке получаемых данных.

Процедуры очистки FIFO

Исходя из вышесказанного, самым правильным маршрутом является очищение всех FIFO перед установкой соединения, будь то первичная установка соединения после включения питания, или повторная установка соединения после разрыва соединения.

Исходя из тех же причин, не рекомендуется к использованию режим AUTO_SPEED, так как он восстанавливает соединение без очистки FIFO, что может приводить к некорректной передаче данных.

Для микросхемы 1892ВМ14Я полный сброс всех FIFO производится записью единицы в бит MODE_CR[6]. Для микросхем 1892ВМ8Я, 1892ВМ7Я, 1892ХД1Я необходимы более сложные алгоритмы, описанные ниже.

Очистка FIFO RX DATA

Очистка приемного FIFO данных осуществляется с помощью соответствующего DMA. Канал DMA настраивается на прием максимального количества данных, которое может быть размещено в приемном FIFO данных. Можно задать прием заведомо большего количества данных, это не принципиально. DMA будет забирать данные из FIFO до тех пор, пока FIFO не опустошится. В программе необходимо дождаться этого момента, после чего остановить DMA. Приемное FIFO остановлено.

Важные нюансы:

  1. Ожидать можно с помощью таймаута, либо с помощью чтения поля WCX регистра CSR DMA. Если поле WCX перестало менять свое значение - значит, DMA больше ничего не вычитывает из FIFO. Значит, вычитывать нечего, и процедура завершена.

  2. В микросхемах 1892ВМ8Я, 1892ХД1Я, 1892ВМ7Я существуют особенности процедуры останова DMA, отраженные в руководстве пользователя на микросхему. Их в данном случае также необходимо учитывать.

Очистка FIFO RX DESC

Очистка приемного FIFO дескрипторов осуществляется аналогично очистке приемного FIFO данных.

Очистка FIFO TX DATA и FIFO TX DESC

Возможны два сценария:

  1. В передающем FIFO данных остались данные, для которых нет соответствующего дескриптора. Они не будут переданы до получения соответствующего дескриптора. Установить, сколько таких данных находится в FIFO, имеющимися средствами невозможно.

  2. В передающем FIFO данных остались данные, а в FIFO дескрипторов - дескрипторы неотправленных пакетов.

Во втором случае надо сначала убедиться в отсутствии "лишних" дескрипторов в FIFO дескрипторов, и после этого приступать к очистке FIFO данных.

Общий алгоритм очистки таков:

  • Включается режим Loopback (установкой в единицу бита MODE_CR[13]);
  • DMA приема данных включается на прием некоторого количества данных, заведомо большего, чем размер передающего буфера;
  • Проверяется, есть ли изменения поля WCX в регистре CSR принимающего канала DMA. Если изменения есть - значит, передатчик отправляет оставшиеся данные в соответствии с оставшимися дескрипторами. Следует ожидать, пока поле WCX не перестанет изменяться;
  • Если данные перестали передаваться - значит, либо отработаны все дескрипторы из FIFO дескрипторов (но данные могли остаться в FIFO данных), либо выданы все данные из FIFO данных (но дескрипторы могут еще оставаться в FIFO дескрипторов);
  • Чтобы проверить, остались ли неотработанные дескрипторы, необходимо через DMA данных передать одно слово и проверить состояние поля WCX в принимающем канале DMA. Если оно изменилось - значит, в передающем FIFO дескрипторов остались неотработанные дескрипторы. Необходимо формировать и передавать через DMA данных по одному слову, пока у DMA приемника не перестанет меняться поле WCX - это будет значит, что все дескрипторы отработаны и FIFO дескрипторов на передачу очищено;
  • Далее необходимо окончательно очистить передающее FIFO данных. Для этого формируется и передается в передатчик дескриптор на передачу одного байта;
  • Проверяется, изменился ли счетчик WCX в канале DMA приема данных. Если изменился - значит, байт был отправлен и получен, и нужно снова формировать и передавать дескриптор;
  • Если счетчик WCX в канале DMA приема данных не изменился - значит, передающее FIFO данных очищено и в нем больше нет данных, и более формировать дескриптор не требуется;
  • Для завершения процедуры необходимо, чтобы отработал последний переданный в передатчик дескриптор. Для этого DMA данных передатчика должно передать из памяти одно слово данных. Оно будет передано, после чего оба FIFO очищены.

Установка соединения

Канал SpaceWire для передачи данных должен сначала установить соединение. Без этого передача данных невозможно. Исключение составляет режим однонаправленной передачи, который, однако, достаточно редко используется и в данном случае не рассматривается. Чтобы установить соединение, необходимо, чтобы порт начал посылать в канал служебные символы (подробнее о служебных символах– в стандарте SpaceWire), и начал получать ответный поток символов от второго абонента. Собственно говоря, если данный поток служебных символов прекращается – соединение разрывается.

Чтобы этот поток служебных символов начал передаваться (и, соответственно, приниматься) – необходимо выполнить следующие действия:

  1. Включить PLL, формирующую частоту передачи по SpaceWire и выставить такой множитель PLL, чтобы скорость передачи была равна 10 Мбит/с. Это и предыдущее действие выполняется записью в регистр TX_SPEED. Для процессора 1892ВМ12Т в этот регистр необходимо записать значение 0x302. Биты TX_SPEED[9:8] разрешают работу PLL, а биты TX_SPEED[7:0] содержат множитель. Опорная частота PLL в данном процессоре получается из частоты на входе XTI, поделенной на 4. При частоте XTI 10 МГц опорная частота PLL контроллера SpaceWire – 2,5 МГц, поэтому равна 5 Мбит/с*TX_SPEED[7:0]. Соединение должно устанавливать только на частоте 10 Мбит/с;
  2. В управляющем регистре установить в ноль разряд «LinkDisabled» и установить в единицу разряды LinkStart и/или AutoStart. Если установить в единицу только бит AutoStart – порт SpaceWire не будет сам отправлять поток служебных символов, пока не получит этих символов от второго абонента. В случае установки только LinkStart – порт начнет отправлять поток служебных символов сразу.
  3. Далее порт SpaceWire пытается установить соединение. Необходимо дождаться, когда оно будет установлено. Об этом сигнализирует поле LINK_STATE в регистре STATUS (разряды [7:5]). Состоянию Run (то есть, установленному соединению) соответствует значение «5».
  4. Далее желательно провести проверку наличия соединения.

Объем проверок для построения отказоустойчивой системы должен включать в себя, как минимум:

  • проверку значения регистра RX_SPEED. В регистре RX_SPEED содержится скорость приема данных, вычисляемая аппаратно контроллером SpaceWire;
  • отсылку и прием тестового пакета, подтверждающего наличие соединения. В случае, если от второго абонента не приходит тестовый пакет – считается, что соединения нет. Данное требование не определено стандартом SpaceWire, так как относится к протоколу более высокого уровня. Тем не менее, опыт показывает, что наличие такой проверки крайне желательно.

В процессе установки соединения по каналу SpaceWire периоды отсылки пачек служебных символов чередуются с периодами «молчания», и длительности этих периодов строго заданы в стандарте SpaceWire. В процессорах серии «Мультикор» длительность этих периодов привязана к тактовой частоте CPU-ядра.

По умолчанию подразумевается, что тактовая частота CPU-ядра – 100 МГц, и исходя из этого рассчитывается длительность вышеупомянутых периодов. В случае, если CPU-ядро работает на другой частоте, необходимо записать в поле TIMING регистра TX_SPEED значение тактовой частоты CPU в мегагерцах, поделенное на 10. По умолчанию запись в это поле запрещена, чтобы разрешить ее – необходимо установить в единицу бит COEFF_10_wr регистра MODE_CR. Процедура установки соединения, таким образом, может выглядеть следующим образом:

// частота процессора в МГц
#define CPU_FREQ 80

// таймаут соединения в тактах процессора – 0.1 секунды
#define CONNECT_TIMEOUT ((CPU_FREQ*1000000)/10);

// функция для отсчета таймаутов
unsigned int GetCP0_Count() {
unsigned int result;
asm volatile ("mfc0 %0, $9" :"=r"(result));
return result;
}

void SWIC_setTiming() {
MODE_CR |= (1<<14);
TX_SPEED |= (CPU_FREQ/10)<<20;
MODE_CR &= ~(1<<14);
}

unsigned int SWIC_tryToConnect() {
// момент начала установки соединения
unsigned int start_connect_time;
SWIC_setTiming();
// выключаем контроллер и PLL
TX_SPEED = 0;
MODE_CR = 0x41;
// включаем PLL и устанавливаем скорость обмена 10 Мбит/с
TX_SPEED = 0x302;
// устанавливаем биты LinkStart и AutoStart
MODE_CR = 0x6;
// фиксируем время начала установки соединения
start_connect_time = GetCP0_Count();
while ( (STATUS & (0xE0) != 0xA0 )) {
if (GetCP0_Count()-start_connect_time) > CONNECT_TIMEOUT) {
break;
}
}
if ( (STATUS & (0xE0) != 0xA0 || (RX_SPEED==0) ) {
// соединение установить не удалось
return 0;
}
return 1;
}

Соединение не будет установлено, если приемные FIFO канала SpaceWire заполнены данными. Вследствие этого необходимо перед установкой соединения произвести процедуру очистки приемных FIFO:

void SWIC_clearRxFifo() {
INT csr_rx_des, prev_csr_rx_des=0;
INT csr_rx_dat, prev_csr_rx_dat=0;
IR_SWIC_RX_DES = DESC_RX_ADDR;
IR_SWIC_RX_DAT = DATA_RX_ADDR;
CSR_SWIC_RX_DES = (0xFFFF<<16) | 1;
CSR_SWIC_RX_DAT = (0xFFFF<<16) | 1;

while (1) {
csr_rx_des = CSR_SWIC_RX_DES;
if ( (csr_rx_des&(0xFFFF<<16)) == (prev_csr_rx_des&(0xFFFF<<16)) ) {
break;
}
prev_csr_rx_des = csr_rx_des;
}

while (1) {
csr_rx_dat = CSR_SWIC_RX_dat;
if ( (csr_rx_dat&(0xFFFF<<16)) == (prev_csr_rx_dat&(0xFFFF<<16)) ) {
break;
}
prev_csr_rx_dat = csr_rx_dat;
}

CSR_SWIC_RX_DES = 0;
CSR_SWIC_RX_DAT = 0;
}

Микросхемы 1892ВМ7Я, 1892ВМ8Я и 1892ХД1Я имеют особенность реализации каналов DMA SpaceWire. Она заключается в том, что когда канал DMA запущен (бит RUN выставлен в единицу), останов канала должен производиться следующим образом:

  • запись нуля в разряд RUN;
  • передача каналом DMA хотя бы одного слова данных.

На практике это значит, что для останова принимающего канала DMA необходимо записать ноль в разряд RUN регистра CSR, после чего дождаться приема служебного пакета со стороны второго абонента. Такой обмен необходимо закладывать в высокоуровневый протокол, используемый в сети.

Установка рабочей скорости обмена

Максимальная пропускная способность канала SpaceWire равна 0.8 от установленной битовой скорости, так как 8 бит данных в канале SpaceWire представлены 10-битовым словом. 1 бит - признак "данные/служебный символ" и 1 бит - четность. То есть, максимальная битовая скорость 400 Мбит/с (по стандарту) - это максимальная пропускная способность 320 Мбит/с.

Для установки требуемой скорости обмена необходимо записать в регистр TX_SPEED соответствующий множитель PLL. Важно понимать, что несмотря на гарантированную способность микросхемы работать на заявленной частоте обмена, многое зависит также от линий передачи. Поэтому выставить множитель PLL – недостаточно для получения требуемой скорости обмена. Необходимо также проконтролировать, что соединение после этого не разорвалось, и только потом приступать непосредственно к пересылке данных. Для проверки состояния соединения необходимо удостовериться, что поле LINK_STATE регистра STATUS по-прежнему соответствует состоянию Run. В случае возникновения флагов ошибок в разрядах STATUS[3:0] необходимо обнулить их. Установка рабочей скорости может быть выполнена, например, так:

// таймаут для проверки соединения в тактах CPU. 0.1 секунда
#define CONNECT_CHECK_TIMEOUT ((CPU_FREQ*1000000)/10)

// параметр – желаемая скорость в мегабитах
unsigned int SWIC_setSpeed(unsigned int speed) {
unsigned int set_speed_time;
TX_SPEED = (3<<8) | (speed/5);
set_speed_time = GetCP0_Count();

while ( (GetCP0_Count() - set_speed_time) < CONNECT_CHECK_TIMEOUT) {
if ( STATUS&0xE0 != 0xA0) {
return 0;
}
}

if ( ( (STATUS&0xE0) != 0xA0) || ( (STATUS&0xF) != 0 ) ) {
return 0;
}

return 1;
}

Передача данных

Как уже говорилось выше, в отличие от других периферийных портов (например, LPORT, SPI, UART), в канал SpaceWire нельзя отправить «просто байт» или «просто слово». Это связано с тем, что SpaceWire, в отличие от упомянутых интерфейсов, оперирует понятием «пакет данных». Пакет в терминологии SpaceWire – это последовательность байтов данных с завершающим символом конца пакета (это специальный служебный символ). Конец пакета может быть корректным (символ EOP – End of packet) или некорректным (символ EEP – Error end of packet). Подробнее о символах и их представлении рассказано в стандарте SpaceWire.

В силу вышеизложенных причин, принята следующая концепция: контроллер SpaceWire должен получить так называемый дескриптор для передачи, в котором будет указано количество байт для передачи в канал. После этого контроллер начнет пересылать приходящие из памяти данные в канал. Когда будет передано заданное количество байт – контроллер сформирует символ конца пакета EOP и также передаст его в канал. Поэтому в реализации SpaceWire в микросхемах серии «Мультикор» блок TX_BUFFER содержит в своем составе два FIFO. Одно FIFO (FIFO данных) принимает данные из памяти и готовит их для передачи в канал. Второе FIFO (FIFO дескрипторов) принимает из памяти дескрипторы для передачи.

В случае, когда в FIFO дескрипторов передается один дескриптор, контроллер SpaceWire расшифровывает его, после чего готов к передаче заданного числа байт. Каждое слово, пришедшее в FIFO данных, передается в канал SpaceWire, до тех пор, пока не будет передано заданное число байт. Если в FIFO данных пришло меньшее количество данных – контроллер SpaceWire будет ожидать получения следующей порции данных, не отправляя в канал символ конца пакета. Если в FIFO данных пришло большее количество данных – в канал будет отправлено то количество байт, которое указано в дескрипторе. Все остальные данные останутся в FIFO данных до получения следующего дескриптора.

Доступ к FIFO дескрипторов и данных SpaceWire возможен только со стороны каналов DMA. Для передачи данных и дескрипторов имеются отдельные каналы DMA. Ниже приведен пример кода, отсылающего пакет в канал SpaceWire. Следует учитывать, что каналы DMA SpaceWire в микросхемах серии «Мультикор» оперируют 32- и 64-разрядными словами. Адрес начала пакета в памяти должен быть выровнен по границе соответствующего слова. Пример функции, отсылающей пакет, приведен ниже.

// длина пакета в байтах
#define ARRAY_LEN 256
// адрес выровнен по границе 64-разрядного слова
unsigned char swic_packet[ARRAY_LEN] __attribute__ ((aligned(8)));
// параметры – указатель на адрес передаваемых данных и
// длина передаваемого массива в байтах
void SWIC_sendPacket(unsigned int *array, unsigned int len) {
// дескриптор тоже передается посредством DMA
// поэтому его адрес тоже должен быть выровнен
unsigned int descriptor[2] __attribute__ ((aligned(8)));
// формируем дескриптор
descriptor[0] = 0xA0000000 | len;
// задаем адрес дескриптора для канала DMA дескрипторов
// каналы DMA оперируют физическими адресами
IR_SWIC_TX_DES0 = get_phy_addr((unsigned int) descriptor);
// задаем адрес начала пакета для канала DMA данных
IR_SWIC_TX_DAT0 = get_phy_addr((unsigned int) array);
// запускаем канал DMA дескрипторов на передачу одного слова
// поле WCX=0 – одно слово для передачи
// поле RUN=1 – передача запущена
CSR_SWIC_TX_DES0 = 1;
// запускаем канал DMA данных на передачу
// поле WCX=(len/8-1) – канал DMA оперирует 64-разрядными словами
// значение должно быть на единицу меньше, чем количество
// передаваемых слов
CSR_SWIC_TX_DAT0 = ((len/8-1)<<16) | 1;
// ожидаем окончания работы DMA данных
while (RUN_SWIC_TX_DAT0&1) ; // пока выставлен бит Run
// канал DMA отработал, дожидаемся, чтоб данных в FIFO SpaceWire
// также не осталось
while ( !( STATUS & (1<<11) ) ) ; // пока не станет нулем бит TX_BUF_EMPTY
}

Приведенный алгоритм требует следующих замечаний:

  1. Ожидается именно окончание работы канала DMA данных. Окончание работы канала DMA дескрипторов не гарантирует, что пересылка данных хотя бы началась;
  2. В ряде случае требуется во время отсылки данных выполнять другие действия. Реализация неблокирующего вызова функции SWIC_sendPacket будет зависеть от конкретной системы, в которой она будет использоваться. Как правило, для этого используются прерывания. В частности, может использоваться прерывание от канала DMA данных;
  3. Дескриптор задается в виде массива из двух 32-разрядных слов. Так как DMA оперирует 64-разрядными словами, передаваться в контроллер SpaceWire будут оба слова. При этом использоваться будет только младшее (расположенное по младшему адресу). Второе слово объявляется для прозрачности.
  4. Алгоритм будет некорректно работать в случае, если длина пакета не кратна 8 байтам. В этом случае необходимо задавать в поле WCX на одно слово больше. Алгоритм с учетом этого выглядит так:
void SWIC_sendPacket(unsigned int *array, unsigned int len) {
// дескриптор тоже передается посредством DMA
// поэтому его адрес тоже должен быть выровнен
unsigned int descriptor[2] __attribute__ ((aligned(8)));
// формируем дескриптор
descriptor[0] = 0xA0000000 | len;
// задаем адрес дескриптора для канала DMA дескрипторов
// каналы DMA оперируют физическими адресами
IR_SWIC_TX_DES0 = get_phy_addr((unsigned int) descriptor);
// задаем адрес начала пакета для канала DMA данных
IR_SWIC_TX_DAT0 = get_phy_addr((unsigned int) array);
// запускаем канал DMA дескрипторов на передачу одного слова
// поле WCX=0 – одно слово для передачи
// поле RUN=1 – передача запущена
CSR_SWIC_TX_DES0 = 1;
// запускаем канал DMA данных на передачу
// поле WCX=(len/8-1) – канал DMA оперирует 64-разрядными словами
// значение должно быть на единицу меньше, чем количество
// передаваемых слов
if (len%8) {// если длина не кратна 8 байтам
CSR_SWIC_TX_DAT0 = ((len/8)<<16) | 1;
}
else {
CSR_SWIC_TX_DAT0 = ((len/8-1)<<16) | 1;
}
// ожидаем окончания работы DMA данных
while (RUN_SWIC_TX_DAT0&1) ; // пока выставлен бит Run
// канал DMA отработал, дожидаемся, чтоб данных в FIFO SpaceWire
// также не осталось
while ( !( STATUS & (1<<11) ) ) ; // пока не станет нулем бит TX_BUF_EMPTY
}

void SWIC_sendPacket(unsigned int *array, unsigned int len) {
// дескриптор тоже передается посредством DMA
// поэтому его адрес тоже должен быть выровнен
unsigned int descriptor[2] __attribute__ ((aligned(8)));
// формируем дескриптор
descriptor[0] = 0xA0000000 | len;
// задаем адрес дескриптора для канала DMA дескрипторов
// каналы DMA оперируют физическими адресами
IR_SWIC_TX_DES0 = get_phy_addr((unsigned int) descriptor);
// задаем адрес начала пакета для канала DMA данных
IR_SWIC_TX_DAT0 = get_phy_addr((unsigned int) array);
// запускаем канал DMA дескрипторов на передачу одного слова
// поле WCX=0 – одно слово для передачи
// поле RUN=1 – передача запущена
CSR_SWIC_TX_DES0 = 1;
// запускаем канал DMA данных на передачу
// поле WCX=(len/8-1) – канал DMA оперирует 64-разрядными словами
// значение должно быть на единицу меньше, чем количество
// передаваемых слов
if (len%8) {// если длина не кратна 8 байтам
CSR_SWIC_TX_DAT0 = ((len/8)<<16) | 1;
}
else {
CSR_SWIC_TX_DAT0 = ((len/8-1)<<16) | 1;
}
// ожидаем окончания работы DMA данных
while (RUN_SWIC_TX_DAT0&1) ; // пока выставлен бит Run
// канал DMA отработал, дожидаемся, чтоб данных в FIFO SpaceWire
// также не осталось
while ( !(STATUS & (1<<11) ) ) ; // пока не станет нулем бит TX_BUF_EMPTY
}

Прием данных

Прием данных по каналам SpaceWire осуществляется следующим образом. После приема каждого из символов контроллер SpaceWire определяет, является ли он служебным символом или символом данных. Если это символ данных – он передается в FIFO данных, а счетчик байтов данных будет инкрементирован. Если это служебный символ конца пакета (EOP или EEP) – будет сформирован дескриптор с соответствующим признаком валидности. В поле длины будет сохранено значение счетчика байт данных. Сформированный дескриптор будет передан в FIFO дескрипторов. Поведение контроллера при приеме других служебных символов рассмотрено в отдельном разделе.

Таким образом, задача приема данных по SpaceWire сводится к запуску принимающих каналов DMA данных и дескрипторов, и последующему ожиданию завершения работы DMA дескрипторов. Если обмен не ведется пакетами фиксированной длины, только формирование дескриптора может служить признаком приема пакета данных. Пока не принят символ EEP или EOP – пакет не принят. В противном случае, можно ожидать и окончания Исходя из этого, функция, осуществляющая прием пакета, может выглядеть так:

// максимальная длина пакета
#define MAX_PACKET_LEN 1024

unsigned char data_buffer[ARRAY_LEN] __attribute__ ((aligned(8)));
// параметры – адрес приемного буфера,
// адрес переменной, содержащей длину принятого пакета
// возвращает 1, если пакет принят нормально (EOP), 0 – если нет (EEP)
unsigned int SWIC_receivePacket(unsigned int *data_buffer, unsigned int &packet_len) {
unsigned int descriptor[2] = {0, 0} __attribute__ ((aligned(8)));

IR_SWIC_RX_DES0 = get_phy_addr((unsigned int) &descriptor);
IR_SWIC_RX_DAT0 = get_phy_addr((unsigned int) data_buffer);
CSR_SWIC_RX_DES0 = 1; // прием одного дескриптора (пакета)
CSR_SWIC_RX_DAT0 = ((MAX_PACKET_LEN/8)<<16) | 1;

while (RUN_SWIC_RX_DES0&1) ;

*packet_len = descriptor[0] & 0xFFFFFFF;
if ( (descriptor[0]&0xF0000000) != 0xA0000000 ) {
return 0;
}
else {
return 1;
}
}

Примечания к приведенному алгоритму:

  1. Аналогично алгоритму отсылки пакета, в случае необходимости реализации неблокирующего вызова, это можно реализовать с помощью прерываний, на этот раз – от канала DMA дескрипторов;
  2. Массив для приема дескрипторов явно задается заполненным нулями. Это связано с тем, что в случае приема ошибочного пакета (EEP) разряд 31 дескриптора не обнуляется, что может привести к некорректному результату проверки, если не обнулить этот разряд заранее.

Служебные символы и управляющие коды

SpaceWire предусматривает несколько служебных символов и управляющих кодов, которые подробно рассмотрены в стандарте. Здесь же будет приведена краткая информация по ним.

СимволОписание
NULLСлужебный символ, передаваемый всегда, когда не передаются данные или другие управляющие коды/служебные символы. Необходим для поддержания соединения (и определения разрыва соединения)
FCT (Flow control token)
EOP (Normal end of packet)Служебный символ, сообщающий о корректном завершении пакета
EEP (Error end of packet)Служебный символ, сообщающий об ошибочном завершении пакета

Помимо вышеуказанного, в стандарте SpaceWire реализована возможность передачи маркеров времени и кодов распределенных прерываний. С их помощью возможна синхронизация узлов сети между собой. Для передачи маркера времени необходимо записать значение маркера в регистр TX_CODE. После этого, если соединение по каналу SpaceWire установлено, маркер будет немедленно передан в сеть (в случае, если в этот момент происходит передача пакета – она будет приостановлена до завершения передачи маркера времени).

По приему маркера времени контроллер SpaceWire выставляет отдельный флаг в одном из регистров. Данный флаг также транслируется в регистр запросов прерываний. Соответственно, обработка полученного маркера времени возможна по прерыванию. Механизм передачи кодов распределенных прерываний полностью аналогичен механизму передачи маркеров времени.

Коммутация пакетов Spacewire и протокол RMAP

Поскольку SpaceWire является интерфейсом типа «точка-точка», для построения сети с большим количеством абонентов удобнее всего использовать коммутаторы SpaceWire. Коммутаторы SpaceWire в серии «Мультикор» представлены несколькими микросхемами, имеющими в своем составе коммутационную матрицу, управляющее CPU-ядро архитектуры MIPS32 и ряд периферийных блоков, необходимых для подключения ПЗУ (где хранится управляющее ПО коммутатора) и другой обвязки. На сегодняшний день программирование коммутаторов конечным пользователем не предусматривается, к микросхеме предоставляется бинарный файл управляющего ПО коммутатора, который должен быть записан в ПЗУ, подключенное к микросхеме коммутатора. Подробнее об этом написано в соответствующей документации. Здесь же будет чуть подробнее рассказано о маршрутизации в сетях SpaceWire.

Таблица маршрутизации
АдресПорт 0Порт 1Порт 2Порт 3Порт 4
Внутренний порт конфигурации010000
Физические выходные порты 101000
200100
Логические адреса, отображающиеся на физические выходные порты 3201000
3300100
3400001
Резервный 25500000

Согласно стандарту SpaceWire, первый байт пакета содержит в себе адрес узла, в который он направлен. В случае приема пакета коммутатором, первый байт рассматривается как номер строки таблицы маршрутизации. Строка таблицы маршрутизации – это слово данных, в котором младшие 16 разрядов соответствуют шестнадцати каналам коммутатора. При получении пакета коммутатор вычитывает строку маршрутизации за номером, соответствующим значению первого байта, после чего направляет данные в каналы с номерами, соответствующими номерам установленных в единицу разрядов вычитанного слова.

При этом буферизации пакета не производится – пакет перенаправляется сразу же после получения первого байта. Первые 16 строк таблицы маршрутизации имеют жестко заданные значения и не могут быть изменены. Строке 1 соответствует первый канал, строке два – второй, и так далее. То есть, пересылка пакета, в котором адресный бит имеет значение от 1 до 16, произойдет только в один канал с соответствующим номером.

Строки 33-255 таблицы маршрутизации могут быть изменены. Поэтому с их помощью можно организоваться широковещательную рассылку по нескольким каналам коммутатора, выставив в единицу несколько бит одновременно.

Помимо этого, коммутаторы SpaceWire реализуют так называемую адаптивную групповую маршрутизацию. Каждому каналу SpaceWire соответствует один регистр ADG_ROUTx (где x – номер канала). Если требуемый канал не соединен или выключен (LinkDisabled=1), коммутатор анализирует регистр ADG_ROUT и перенаправляет пакет в альтернативные каналы, определенные в регистре ADG_ROUT. Подробнее это описано в руководстве пользователя на коммутатор.

Если адресный байт пакета равен нулю – считается, что он адресован в так называемый конфигурационный порт узла SpaceWire. Предполагается в этом случае, что пакет соответствует протоколу RMAP (remote memory access protocol). В зависимости от его содержания, пакет содержит либо данные, подлежащие записи в указанный адрес памяти, либо запрос на получение данных из требуемого адреса памяти.

В коммутаторе SpaceWire использование пакетов RMAP, адресованных в нулевой порт, позволяет изменять таблицу маршрутизации, настройки каналов SpaceWire и еще некоторые параметры. Обработка пакетов RMAP реализована программно на CPU-ядре. В некоторых микросхемах (например, 1892ХД5Т) обработка пакетов RMAP реализована аппаратно. В микросхемах процессоров, содержащих каналы SpaceWire, а также в микросхемах «мостах» (1892ХД1Я, 1892ХД4Ф) аппаратной поддержки RMAP не предусмотрено, она при необходимости должна быть реализована программно в ПО, разрабатываемом пользователем. Протокол RMAP определен стандартом ECSS-E-ST-50-52C, и более подробно описан в нем.

Физический уровень

Терминирующие резисторы

Терминирующие резисторы номиналом 100 Ом реализованы в приемниках SpaceWire на кристалле. Установка внешних терминирующих резисторов не требуется.

Failsafe-резисторы и "ложные соединения"

При установке соединения передатчик SpaceWire начинает отсылать в канал символы NULL. Также для установки соединения порт ожидает приема NULL-ов от удаленного порта.

Если линии приемника никуда не подключены, или подключены к выключенному передатчику, дифференциальное напряжение на них близко к нулю. Когда включается передатчик, передаваемые NULL-ы "наводятся" на линии приемника. Наведенное дифнапряжение на линиях приемника невелико, однако этого достаточно, чтобы приемник "воспринял" NULL-ы. После этого порт переходит в состояние "соединение установлено", несмотря на фактическое отсутствие второго абонента. Это происходит не всегда и не на всех портах SpaceWire, но вероятность такого события является ненулевой. Это событие условно обозначается как "ложное соединение".

Проблемы нет, если приемник подключен к включенному абоненту SpaceWire. В этом случае передатчик удаленного абонента обеспечивает достаточный размах дифнапряжения на входах приемника, и все наводки на фоне этого являются несущественными.

Чтобы исключить ложные соединения, необходимо подключать к линиям приемника резисторы, подтягивающие линии P и M к разным уровням (далее - failsafe-резисторы). Это обеспечивает на входах дифнапряжение, достаточное для того, чтобы наводки от передатчика были несущественными.

Номинал и схема включения failsafe-резисторов для конкретного типа микросхем указаны в руководстве пользователя на микросхему.

примечание

Данная особенность не является специфичной для контроллеров SpaceWire в микросхемах АО НПЦ "ЭЛВИС". Ряд сторонних устройств с портами SpaceWire также использует аналогичные failsafe-резисторы.

Разрыв соединения при повышении скорости обмена

Помимо параметров передатчика и приемника, на максимальную скорость обмена влияет качество линий передачи. Из практики - кабели длиной более 20 метров не обеспечивают скорости обмена выше 100 Мбит/с, несмотря на то, что сами передатчики и приемники в микросхеме способны работать на более высоких скоростях. Поэтому рекомендуется в ПО проверять соединение после повышения скорости передачи, даже в случае установки заведомо пониженной скорости.

Отказы портов SpaceWire

Из практики анализа отказов - самой частой причиной отказов является "выбитый" вывод LVDS. Это является следствием воздействия повышенного напряжения - либо статического электричества, либо подключение "на горячую", либо подключение двух SpaceWire-устройств без общей "земли".

Предварительная диагностика подобного отказа может производиться на стороне пользователя. Она сводится к измерению сопротивления всех выводов порта SpaceWire к "земле" и к питанию 3.3В. Сопротивление менее 1 кОм говорит о том, что с выводом порта SpaceWire не все в порядке.

Общая "земля" и гальваническая развязка

Стандарт SpaceWire не предполагает гальванической развязки. Поэтому, так или иначе, кабели SpaceWire должны содержать общий сигнал «земли». Если обратить внимание на кабель SpaceWire, описанный в стандарте, видно, что общая «земля» двух устройств, соединенных по SpaceWire, соединяет корпуса разъемов через внешнюю экранирующую оплетку кабеля. Фактически, это значит, что для работы кабеля, соответствующего стандарту, необходимо соединять корпус разъема на плате с «землей» этой платы. В частности, такое решение использовано и в устройстве USB Brick фирмы StarDundee. В отладочных модулях и другой аппаратуре АО НПЦ «ЭЛВИС» для работы по SpaceWire используется альтернативный вариант. Используемый кабель для обмена по SpaceWire – обычная витая пара. Контакты №3 разъемов SpaceWire двух устройств соединены посредством экранирующей оплетки кабеля. Опыт работы показывает, что использование такого кабеля обеспечивает корректную работу микросхем АО НПЦ «ЭЛВИС» на скоростях передачи данных, гарантированных документацией.

Логический уровень

Зависимость скорости передачи от настроек удаленного абонента

Приемник принимает данные по SpaceWire на той скорости, которая настроена у передатчика. Иными словами, если мы хотим передавать на скорости 400 Мбит/с - нам нужно только настроить передатчик на эту скорость. Приемник просто примет это как данность.

Однако есть нюанс, который необходимо учитывать в данном случае. Передатчик отсылает данные только тогда, когда получит от приемника подтверждение готовности к приему. Таким подтверждением является получение служебного символа FCT - оно говорит передатчику, что приемник готов принять очередные несколько байт. Если принимающий удаленный абонент настроен на скорость передачи 10 Мбит/с (базовую при установке соединения), то максимальный темп отсылки символов FCT позволит отсылать этому абоненту данные с максимальной пропускной способностью ~100 Мбит/с. Поэтому, даже если узел должен только получать данные, для обеспечения пропускной способности рекомендуется повышать его скорость передачи после установки соединения.