Sygnał DMX
Sygnał przesyłany poprzez DMX jest konwertowany w układzie U4, natomiast układ U6 typu SC16IS760 odbiera dane. Można je z niego odczytać poprzez interfejs I2C lub SPI. W urządzeniu wybrano tryb SPI (nóżka 8 zwarta z masą), który jest dużo szybszy. Może pracować z szybkością do 15 Mb/s (1,5 MB/s) i nie ma potrzeby adresowania. Układ SC16IS760 to interesujący kontroler UART, ma 64 bajtowy bufor FIFO dla nadawania i odbioru a na poziomie rejestrów jest kompatybilny z 16C55x/16C45x. Ponadto może automatycznie sterować/reagować na linie sprzętowego przesyłu danych RTS/CTS. Taką funkcję miały tylko dwa układy: intelowski 8251 i Z-80 SIO. Inną zaletą kontrolera jest automatyczna zmiana kierunku transmisji dla RS485/422. Układ może sprzętowo obsługiwać Xon/Xoff składające się z jednego lub dwu bajtów. Dostępne są jeden lub dwa interfejsy UART w jednej obudowie.
Dodatkowe 8 (10) portów IO z możliwością generowania przerwań też jest zaletą. Często umożliwi to rezygnację z popularnego PCF8574 a pracuje w trybie FAST (400 kHz), a nie standardowym (100 kHz). Dodatkowe rejestry kontrolera (23 rejestry na 16 adresach, a nie 10 na 8 jak w przypadku 16C55x) umożliwiają ustawienie progu sygnalizacji zapełniania FIFO w zakresie 4...64 bajty z rozdzielczością 4 bajtów. Inne rejestry przechowują informacje o liczbie znaków w FIFO nadawczym i odbiorczym. W urządzeniu skorzystano z tej funkcji.
// Jeśli BREAK lub RX
while( (stat=Read_SC16IS(0, SC16IS_LSR)) & 0b1001){
//==================== Obiór ======================//
// Czy znak w odbiorniku ?
if (stat & 1){
// Jeśli błąd FIFO (w danych znajduje się BREAK)
if (stat & 0x80){
// Czytaj bajt po bajcie
if(!errOv) DekodujDMX(Read_SC16IS(0, SC16IS_RHR));
block = false;
// Jeśli nie ma błędu
} else {
// Czytaj blokowo
byte static buf[64];
// Liczba znaków w FIFO
byte rxlvl = Read_SC16IS(0, SC16IS_RXLVL);
// Czytaj blok
ReadBlock_SC16IS(0, SC16IS_RXLVL, &buf, rxlvl);
if(!errOvr) for(byte x=0; x<rxlvl; x++) DekodujDMX(buf[x]);
}
// Jeśli BREAK
if (stat & 0x10){
errOvr = false;
TimeOutUsbLoock = 1000;
TimLedRxUart = TIM_FLASH_LED; SetLed(LED_RX_UART);
DekodujDMX(0xFFFF);
// Sygnalizacja błędu przepełnienia bufora
} else if (stat & 2+8){
TimLedOvrUart = TIM_FLASH_LED; SetLed(LED_OVR_DMX);
}
}
}
Po wykryciu pojawienia się znaku w kontrolerze UART, wykonywany jest program z listingu 4. Podczas nadawania, także używany jest bufor FIFO. Cała procedura nadawania jest bardziej skomplikowana i oparta na maszynie stanów.
Kontroler UART wymaga jeszcze kilku słów wyjaśnienia. Aby zapewnić funkcjonalną kompatybilność z pierwowzorem i przypadkowo nie uaktywnić dodatkowych funkcji wprowadzono specyficzny sposób dostępu do niektórych rejestrów. Aby dostać się do TCR i TLR należy uaktywnić między innymi bit 4 w EFR. Bit w EFR będzie dostępny natomiast po wpisaniu do LCR wartości $BF. Wszystko jest opisane w nocie katalogowej ale, aby ułatwić zmagania z układem procedura inicjalizacji została pokazana na listingu 5.
//======================================================================//
// Inicjalizuje SC16IS. Jeśli nie wykryje układu zwraca false
//======================================================================//
byte Init_SC16IS(byte slave){
byte hi, lo;
slave &= SC16IS_MAX-1;
SPI_UART_SSh();
// Speed=max, Master, MSB First, SpiMode=0
SpiInit(0, true, true, 0);
#define BAUD_SC16IS_VAL CLK_SC16IS / 1UL / ( BAUD_SC16IS * 16UL)
#define BAUD_SC16IS_VAL_L ( BAUD_SC16IS_VAL & 0xFF )
#define BAUD_SC16IS_VAL_H ( BAUD_SC16IS_VAL >> 8 )
// Udostępnienie EFR
Write_SC16IS(slave, SC16IS_LCR, 0xBF);
// Udostępnienie funkcji rozszerzonych
Write_SC16IS(slave, SC16IS_EFR, 0x10);
// Wybór rejestru prędkości
Write_SC16IS(slave, SC16IS_LCR, 0x80 );
Write_SC16IS(slave, SC16IS_DLL, lo=BAUD_SC16IS_VAL_L);
Write_SC16IS(slave, SC16IS_DLH, hi=BAUD_SC16IS_VAL_H);
//----- Weryfikacja-----
if (Read_SC16IS(slave, SC16IS_DLL) != lo) return(sc16is_st[slave]=false);
if (Read_SC16IS(slave, SC16IS_DLH) != hi) return(sc16is_st[slave]=false);
//B7-latch, B6-BREAK, SetParity, EvenParity, ParityEn, B2-Stop, D1,B0 - Lenght
// Wybór formatu ramki 8N2
Write_SC16IS(slave, SC16IS_LCR, 0b00000111);
// Włączenie FIFO, RX gdy 16 bajtów
Write_SC16IS(slave, SC16IS_FCR, 0b01000001);
// Przerwania odbiorcze
Write_SC16IS(slave, SC16IS_IER, 0b00000001);
return (sc16is_st[slave]=true);
}
Funkcje obsługi układu sprowadzają się do:
byte Write_SC16IS(byte slave, byte reg, byte data)
void WriteBlock_SC16IS(byte slave, byte reg, byte *buf, byte len)
byte Read_SC16IS(byte slave, byte reg)
void ReadBlock_SC16IS(byte slave, byte reg, byte *buf, byte len)
Dodam jeszcze, że zanim zrealizowałem projekt konwertera DMX wykonałem próby dekodowania DMX z użyciem interfejsu UART mikrokontrolera podczas transmisji do WS2812. Ze względu na to, że niezalecane jest używanie innych przerwań blokowanych (SIGNAL lub ISR bez atrybutu NOBLOCK) poza tymi od obsługi diod LED a takimi przerwaniami muszą być przerwania odbiorcze od UART, w przerwaniach nieblokowanych (INTERRUPT lub ISR z atrybutem BLOCK) od timera wywoływanymi co 33 µs (co 3 przerwania 11 µs) sprawdzałem UART.