Dejan Levec

Amblight part 2: Controlling LEDs

After figuring out how to control LEDs with microcontroller I wanted to try controlling it from PC. Firstly I thought of USB via V-USB framework, but I quickly found out that I cannot update LEDs’ color in interrupt routine, because it would interfere with USB data transfer. Since I had additional unused AVR on my table I decided to use it as a USB to serial converter by using AVR-CDC firmware (http://www.recursion.jp/avrcdc/).


(It has a slight delay, but I haven’t been able to find out if it’s because of Stereo Mix, FMOD or both.)

Main controller is currently responsible for receiving data via USART and updating LEDs when enough data is transfered (RGB color for each of 25 LEDs). It uses additional timer interrupt to check for lost connection to remove partially received data to not mess with data received afterwards.

Timer interrupt code checks if it has already elapsed predefined time after last received byte and clears data:

ISR (SIG_OUTPUT_COMPARE0A)
{
int i=0;
time++;

if(time > 4*30) {
for(i = 0;i<25;i++) {
for(SPDR = 0x00; !(SPSR & _BV(SPIF)); );
for(SPDR = 0x00; !(SPSR & _BV(SPIF)); );
for(SPDR = 0x00; !(SPSR & _BV(SPIF)); );
}

current=0;
time=0;
}
}

USART receiver interrupt updates color channel value for current LED and checks if we already received enough data to send it to LEDs connected via SPI:

ISR(SIG_USART_RECV)
{
char ReceivedByte;
int i;

ReceivedByte = UDR0;

diodes[current++]=ReceivedByte;
time=0;

if(current>=25*3) {
current=0;
for(i = 0;i<25*3;i++) {
for(SPDR = diodes[i]; !(SPSR & _BV(SPIF)); );
}
}
}

Everything is controlled from C application using FMOD library for audio spectrum analysis, and Windows serial port communication.

Sample code for initializing and writing data to serial port:

//COM communication
int serial_start(wchar_t *port) {
DCB settings;
int r;

comPort = CreateFile( // http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
port,
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);

if(comPort == INVALID_HANDLE_VALUE) {
return -1;
}

r = GetCommState(
comPort,
&settings
);

if(r == 0) {
return -1;
}

/*
AVR: UCSR0C = (3 << UCSZ00); = no parity, 8 bits
*/
settings.BaudRate=128000;
settings.ByteSize=8;
settings.Parity=NOPARITY;
settings.StopBits=ONESTOPBIT;

r = SetCommState(
comPort,
&settings
);

if(r == 0) {
return -1;
}

return 0;
}

void serial_write(unsigned char *buf, unsigned int length) {
DWORD written = 0;
WriteFile( // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747(v=vs.85).aspx
comPort,
buf,
length,
&written,
NULL
);
}

Leave a Reply

Your email address will not be published. Required fields are marked *