Реверс-инжиниринг протокола записи адресов микросхемы UCS512

в 12:00, , рубрики: DMX512, pic32mx795f512l, UCS512C, программирование микроконтроллеров, реверс-инжиниринг

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

Лента, которую я использую, оснащена яркими RGB-светодиодами SMD 5060 с тремя кристаллами каждый и микросхемами управления UCS512C. Каждый пиксель управляется индивидуально и состоит из шести светодиодов.

Для передачи данных используется стандартный дифференциальный сигнал интерфейса RS485 -два сигнала управления: А и В, что позволяет передавать цифровой сигнал на большое расстояние.

Для управления светодиодной лентой может быть использован любой внешний контроллер с интерфейсом DMX512.

Все хорошо, но есть одно НО. Пиксели на ленте не имеют привычных для ДМХ512 DIP-переключателей для задания ДМХ512 адреса. Установка DMX-адресов в микросхемах UCS512C выполняется при помощи внешнего специализированного редактора. Найти описание на протокол настройки адресов микросхем UCS512C мне так и не удалось. Представленной информации достаточно для создания собственного редактора адресов микросхем UCS512C. Я не гарантирую, что точно понял алгоритм записи адресов. Поэтому, вы используете эту информацию на свой страх и риск. Информация собрана по крупицам и представлена в виде временных диаграмм работы интерфейса с некоторыми пояснениями. Статья предназначена для тех, кто ищет информацию об алгоритме редактирования адресов микросхем UCS512C. И также следует учесть, что это не описание алгоритма от производителя.

На рисунке 1 представлен полностью обмен между контроллером задания адреса и лентой на микросхеме UCS512C. Далее на временных диаграммах Chenal1  - это RS485А , а Chenal2  - это RS485В. Задание адреса происходит передачей двух пакетов. На соответствующих временных диаграммах будет раскрыта структура данных пакетов более детально.

Реверс-инжиниринг протокола записи адресов микросхемы UCS512 - 1

До начала процесса программирования линия А интерфейса RS485 находится в состоянии высокого уровня, линия В интерфейса RS485 – в низком, по крайней мере секунду или более. На временной диаграмме это время Т1. Далее идет импульс сброса 2 секунды. Это интервал Т2. Затем передается первый кадр информации с адресами, следом за первым кадром следует второй импульс сброса. Это интервал Т3. Передается второй кадр информации с адресами. После этого линия А интерфейса RS485 находится в состоянии высокого уровня, а линия В интерфейса RS485 – в низком до момента снятия питания с ленты. Новые адреса будут использоваться после перезагрузки ленты по питанию.

Теперь рассмотрим некоторые особенности передачи данных. Надо отметить, что все данные передаются на скорости 250000 – стандартной для протокола ДМХ512, количество информационных бит 8, количество стоп бит равно 2. Все современные микроконтроллеры имеют соответствующие режимы настройки UART для передачи данных. Для физического уровня интерфейса используются стандартные микросхемы типа MAX485 с соответствующими цепями защиты входов.

Реверс-инжиниринг протокола записи адресов микросхемы UCS512 - 2

Рисунок 2 показывает, что в начале каждого кадра идет передача стартового кода 0х00, причем перед передачей этого кода линия А должна находится в состоянии высокого уровня 20 мкс. Это время Т5. Спустя 100мкс, время Т6, передается пакет установки адреса для первой микросхемы. Эта микросхема первая в цепочке. Затем спустя время Т8, равное 100 мкс, передается второй пакет, третий и так далее по количеству микросхем в ленте. Интервал между передаваемыми байтами 20 мкс. На рисунке 3 и рисунке 4 этот момент виден более четко.

Реверс-инжиниринг протокола записи адресов микросхемы UCS512 - 3
Реверс-инжиниринг протокола записи адресов микросхемы UCS512 - 4

Каждый пакет состоит из восьми байт. Стоит отметить, что порядок следования бит в байте обратный. На рисунке представлены настройки анализатора.

Реверс-инжиниринг протокола записи адресов микросхемы UCS512 - 5

Первые пять байт каждого пакета одинаковые – это 0xAA, 0xF0, 0x34, 0x55, 0xAC. Шестой байт — это признак пакета. Для первого пакета этот байт равен 0x80, а для второго пакета этот байт равен 0xC0. На следующих рисунках это будет видно.

Реверс-инжиниринг протокола записи адресов микросхемы UCS512 - 6

Седьмой и восьмой байт в этом пакете – это сформированный определенным образом адрес для соответствующего пикселя ленты. В представленной программе можно найти этот алгоритм. Хочется отметить, что этот алгоритм вычислен после много часовых поисков разрозненной информации в интернете. Переводе разных отрывочных сообщений об алгоритмах работы микросхемы UCS512C. Программа сделана в виде законченного модуля для микроконтроллера PIC32MX795F512. При желании ее легко можно перенести на другие МК. для инициализации адресов небходимо запустить Init_UCS512C();.

В русскоязычной литературе я не нашел ничего по принципу работы алгоритма задания адресов микросхемы UCS512C.

Вы можете восполнить этот пробел и оставить свои комментарии со ссылками.


//*****************************************************************************
	#define BAUDRATE_DMX512 	250000
	#define BAUDRATE_MAB	 	50000

	//******** Управление СОМ порт3 RS485 ***********
	#define UART3_TX_TRIS		(TRISGbits.TRISG8)
	#define UART3_TX_IO			(PORTGbits.RG8)
	#define INV_UART3_TX_IO()	(LATGINV=_LATG_LATG8_MASK)
	#define SET_UART3_TX_IO()	(LATGSET=_LATG_LATG8_MASK)
	#define CLR_UART3_TX_IO()	(LATGCLR=_LATG_LATG8_MASK)
	
	#define UART3_RX_TRIS		(TRISGbits.TRISG7)
	#define UART3_RX_IO			(PORTGbits.RG7)

	#define RS485RE_TRIS		(TRISGbits.TRISG6)	// управление приемом по RS485
	#define RS485RE				(LATGbits.LATG6)
	#define SET_RS485RE()		(LATGSET=_LATG_LATG6_MASK)
	#define CLR_RS485RE()		(LATGCLR=_LATG_LATG6_MASK)
	#define INV_RS485RE()		(LATGINV=_LATG_LATG6_MASK)

	#define RS485DE_TRIS		(TRISGbits.TRISG9)	// управление передачей по RS485
	#define RS485DE				(LATGbits.LATG9)
	#define SET_RS485DE()		(LATGSET=_LATG_LATG9_MASK)
	#define CLR_RS485DE()		(LATGCLR=_LATG_LATG9_MASK)
	#define INV_RS485DE()		(LATGINV=_LATG_LATG9_MASK)

	#define BEGIN_ADRESS	 	1		// Стартовый адрес
	#define STEP_ADRESS	 		3		// количество каналов в одной микросхеме
	#define NUM_PIXEL	 		96		// количество пикселей в ленте

//*****************************************************************************
void DMX_Delay(DWORD nus) // программная задержка, спешить нам некуда
{
	DWORD i;
	i=8*nus;
	while(i--) {WDTCONSET = _WDTCON_WDTCLR_MASK;}
}
//*****************************************************************************
// вывод одного байта в RS485
void putc_RS485(unsigned char data)	// вывод одного байта через UART
{
	while(!U3BSTAbits.TRMT) {Nop();} // ожидаем окончания предыдущей передачи
	U3BTXREG = data & 0xFF;  
}
//*****************************************************************************
// вывод заданного количества байт из буфера в RS485
void putd_RS485(unsigned char *buffer, unsigned char num)
{
	while(num !=0) 	{putc_RS485(*buffer++); num--; 	DMX_Delay(42);}
}
//*****************************************************************************
void RX_MAX485(void) // переводим на прием MAX485
{
	RS485DE_TRIS=0;					// настроили пин управления DE на выход 
	RS485RE_TRIS=0;					// настроили пин управления RE на выход 
	CLR_RS485DE();					// Запрещаем работу передатчика микросхемы MAX485
	CLR_RS485RE();					// Разрешаем работу приемника микросхемы MAX485
}
//*****************************************************************************
void TX_MAX485(void) // переводим на передачу MAX485
{
	RS485DE_TRIS=0;					// настроили пин управления DE на выход 
	RS485RE_TRIS=0;					// настроили пин управления RE на выход 
	SET_RS485DE();					// Разрешаем работу передатчика микросхемы MAX485
	SET_RS485RE();					// Запрещаем работу приемника микросхемы MAX485
}
//*****************************************************************************
void Stop_UART(void) // Останавливаем работу UART
{
	U3BMODE = 0x0000;				// Останавливаем работу UART
	U3BSTA = 0x00000000;
	IEC2bits.U3BRXIE = 0;			// Запрещаем прерывания приемника UART
	IEC2bits.U3BTXIE = 0;			// Запрещаем прерывания передатчика UART
	IFS2bits.U3BTXIF = 0;			// Сброс флага прерывания приемника UART
	IFS2bits.U3BRXIF = 0;			// Сброс флага прерывания передатчика UART
}
//*****************************************************************************
void Init_UART(void) // Настраиваем работу UART
{
	U3BMODE = 0x8000;				// Разрешаем работу UART , это нужно выполнить до настройки остального
	U3BMODEbits.STSEL = 1;			// количество стоп бит =2
	U3BMODEbits.PDSEL = 0;			// 8-bit данных, без контроля четности
	IPC12bits.U3BIP = 6;			// Priority level 6, но нам не понадобятся прерывания
	U3BSTA = 0x00000000;			//
	U3BSTAbits.URXISEL=0;			// Режим прерываний для приемника по каждому принятому символу
	U3BSTAbits.UTXISEL=0;			// Режим прерываний для передатчика
	U3BSTAbits.URXEN= 0;			// Запрещаем работу приемника UART
	U3BSTAbits.UTXEN= 1;			// Разрешаем работу передатчика UART
	U3BBRG = ((GetPeripheralClock()+8ul*BAUDRATE_DMX512)/16/BAUDRATE_DMX512-1);	// Скорость передачи 250000
	IEC2bits.U3BRXIE = 0;			// Запрещаем прерывания приемника UART
	IEC2bits.U3BTXIE = 0;			// Запрещаем прерывания передатчика UART
	IFS2bits.U3BTXIF = 0;			// Сброс флага прерывания приемника UART
	IFS2bits.U3BRXIF = 0;			// Сброс флага прерывания передатчика UART
}
//*****************************************************************************
void Set_TX_Low(void) // Устанавливаем низкий уровень на пине ТХ
{									// UART нужно остановить , чтобы потом управлять пином ТХ
	Stop_UART();					// Останавливаем работу UART
	UART3_TX_TRIS=0; 				// настроили пин передатчика на выход
	CLR_UART3_TX_IO();				// установили низкий уровень на пине передатчика
}
//*****************************************************************************
void Set_TX_Hight(void) // Устанавливаем высокий уровень на пине ТХ
{
	Stop_UART();					// Останавливаем работу UART
	UART3_TX_TRIS=0; 				// настроили пин передатчика на выход
	SET_UART3_TX_IO();				// установили высокий уровень на пине передатчика
}

//*****************************************************************************
void DMX_Break(void)	// Отправка Break и стартового кода 00
{
	DMX_Delay(12);					// задержка
	putc_RS485(0x00);				// Передали 0 стартового кода
	while(!U3BSTAbits.TRMT)			// дождались окончания передачи
		{WDTCONSET = _WDTCON_WDTCLR_MASK;}
	DMX_Delay(51);					// задержка
}
//*****************************************************************************
unsigned char DMX_Transposition(unsigned char tempchar)  // перестановка битов в байте
{
	unsigned char i;
	unsigned char tempnum;
	i=0;
	tempnum=0;
	
	for(i=0;i<8;i++)
	{
		tempnum=tempnum>>1; 
		tempnum=((tempchar<<i)&0x80)|tempnum; 
	}
	return tempnum;
}
//*****************************************************************************
void Send_Chenge_Adress(unsigned char common,unsigned char tempdata) //  Отправка команды смены адреса
{
    unsigned char data_H,data_L,i,tempadd[8];
   
	tempadd[0]=DMX_Transposition(0xAA);	//
    tempadd[1]=DMX_Transposition(0xF0);	//
    tempadd[2]=DMX_Transposition(0x34);	//
    tempadd[3]=DMX_Transposition(0x55); //
	tempadd[4]=DMX_Transposition(0xAC);	//
    tempadd[5]=DMX_Transposition(common);

	// делаем некую манипуляцию чтоб получить два байта адреса для отправки микросхеме
	data_H=(tempdata>>6)&63;    		//
	data_L=tempdata&63;		   			//
	data_H=(data_H)|0x80;	    		//
	data_L=(data_L)|0x40;	    		//
    tempadd[6]=DMX_Transposition(data_H);
    tempadd[7]=DMX_Transposition(data_L);

	putd_RS485(tempadd,8);
	DMX_Delay(40);							// задержка
}
//*****************************************************************************
	#define BEGIN_ADRESS	 	1		// Стартовый адрес
	#define STEP_ADRESS	 		3		// количество каналов в одной микросхеме
	#define NUM_PIXEL	 		96		// количество пикселей в ленте

//*****************************************************************************
void Init_UCS512C(void)	// инициализация адресов микросхемы ucs512c
{
static DWORD Trtc; 	// Таймер для отсчета интервалов времени
static WORD adress, Schet_pixel; 

CLR_LED_WORK();
Trtc=TickGet();
Set_TX_Hight();							// Устанавливаем высокий уровень на пине ТХ
while(TickGet() - Trtc < TICK_SECOND) {WDTCONSET = _WDTCON_WDTCLR_MASK;}  // Подождать 1 сек перед ресетом

Set_TX_Low();							// Устанавливаем низкий уровень на пине ТХ
Trtc=TickGet();
while(TickGet() - Trtc < TICK_SECOND*2) {WDTCONSET = _WDTCON_WDTCLR_MASK;}  // Подождать 2 сек для ресета
Set_TX_Hight();							// Устанавливаем высокий уровень на пине ТХ

Init_UART();							// Настраиваем работу UART
DMX_Break();							// Отправка Break и стартового кода 00

adress=BEGIN_ADRESS -1;
for(Schet_pixel=0;Schet_pixel<NUM_PIXEL;Schet_pixel++)
	{
	Send_Chenge_Adress(0x80, adress);
	adress=adress+STEP_ADRESS;
	}

Set_TX_Low();							// Устанавливаем низкий уровень на пине ТХ
Trtc=TickGet();
while(TickGet() - Trtc < TICK_SECOND*2) {WDTCONSET = _WDTCON_WDTCLR_MASK;}  // Подождать 2 сек для ресета

Init_UART();							// Настраиваем работу UART
DMX_Break();							// Отправка Break и стартового кода 00

adress=BEGIN_ADRESS;
for(Schet_pixel=0;Schet_pixel<NUM_PIXEL;Schet_pixel++)
	{
	Send_Chenge_Adress(0xC0, adress);
	adress=adress+STEP_ADRESS;
	}
//Set_TX_Hight();							// Устанавливаем высокий уровень на пине ТХ

SET_LED_WORK();							// Индикация окончания процесса записи адресов
while(1) {WDTCONSET = _WDTCON_WDTCLR_MASK;}  // Ждем пока не перегрузят по питанию

}

Автор: Якорев Сергей

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js