rgbyteclock-code/ledcontroller.c
2014-03-17 01:15:28 +01:00

241 lines
4.6 KiB
C

/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <struppi@struppi.name> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return.
* (c) 2014 Stefan Rupp
* ----------------------------------------------------------------------------
*/
/*
* This module tries to control 15 RGB-LEDs
* connected to three daisy-chained
* LED1642GW-ICs from STM.
*/
#include "ledcontroller.h"
#include <string.h>
#include <util/delay.h>
#define NUM_LED1642GW_ICs (3)
#define NUM_LED1642GW_CHANNELS (16)
#define NUM_LED_CHANNELS (NUM_LED1642GW_CHANNELS*NUM_LED1642GW_ICs)
static uint16_t ledbuffer[NUM_LED_CHANNELS];
static int8_t map_lednum_to_channels(uint8_t lednum, uint8_t *channel_r, uint8_t *channel_g, uint8_t *channel_b)
{
uint8_t ret=0;
if (lednum < 14) {
ret = 1;
switch (lednum) {
case 0:
*channel_r = 13;
*channel_g = 14;
*channel_b = 15;
break;
case 1:
*channel_r = 33;
*channel_g = 34;
*channel_b = 35;
break;
case 2:
*channel_r = 36;
*channel_g = 37;
*channel_b = 38;
break;
case 3:
*channel_r = 45;
*channel_g = 46;
*channel_b = 47;
break;
case 4:
*channel_r = 42;
*channel_g = 43;
*channel_b = 44;
break;
case 5:
*channel_r = 39;
*channel_g = 40;
*channel_b = 41;
break;
case 6:
*channel_r = 29;
*channel_g = 30;
*channel_b = 31;
break;
case 7:
*channel_r = 26;
*channel_g = 27;
*channel_b = 28;
break;
case 8:
*channel_r = 23;
*channel_g = 24;
*channel_b = 25;
break;
case 9:
*channel_r = 20;
*channel_g = 21;
*channel_b = 22;
break;
case 10:
*channel_r = 17;
*channel_g = 18;
*channel_b = 19;
break;
case 11:
*channel_r = 10;
*channel_g = 11;
*channel_b = 12;
break;
case 12:
*channel_r = 4;
*channel_g = 5;
*channel_b = 6;
break;
case 13:
*channel_r = 7;
*channel_g = 8;
*channel_b = 9;
break;
default:
ret = 0;
break;
}
}
return ret;
}
static void write_data(uint16_t data, uint8_t le_clocks)
{
uint16_t mask = 0x8000;
int8_t bit;
PORTC &= ~(1<<PC2);
for (bit=15; bit>=le_clocks; bit--) {
PORTC &= ~(1<<PC3);
if(data&mask) { PORTC |= (1<<PC4); }
else { PORTC &= ~(1<<PC4); }
PORTC |= (1<<PC3);
mask >>= 1;
}
PORTC |= (1<<PC2);
for (/*noting to initialize*/; bit>=0; bit--) {
PORTC &= ~(1<<PC3);
if(data&mask) { PORTC |= (1<<PC4); }
else { PORTC &= ~(1<<PC4); }
PORTC |= (1<<PC3);
mask >>= 1;
}
PORTC &= ~(1<<PC3);
PORTC &= ~(1<<PC2);
PORTC &= ~(1<<PC4);
}
static void write_data_latch(uint16_t data)
{
write_data(data, 4);
}
static void write_global_latch(uint16_t data)
{
write_data(data, 6);
}
static void write_no_command(uint16_t data)
{
write_data(data, 0);
}
void led_turn_all_on(void)
{
write_data(0xffff, 2);
_delay_us(10);
write_data(0xffff, 2);
_delay_us(10);
write_data(0xffff, 2);
_delay_us(10);
}
void led_turn_all_off(void)
{
write_data(0x0000, 2);
_delay_us(10);
write_data(0x0000, 2);
_delay_us(10);
write_data(0x0000, 2);
_delay_us(10);
}
void led_init(void)
{
PORTC &= ~(1<<PC3); // SCK
PORTC &= ~(1<<PC4); // DATA
PORTC &= ~(1<<PC2); // LE
DDRC |= (1<<PC3); // SCK
DDRC |= (1<<PC4); // DATA
DDRC |= (1<<PC2); // LE
memset(ledbuffer, 0x00, sizeof(ledbuffer));
led_flush();
}
void led_set(uint8_t lednum, uint16_t red, uint16_t green, uint16_t blue)
{
uint8_t c_r, c_g, c_b;
if ( map_lednum_to_channels(lednum, &c_r, &c_g, &c_b) > 0 ) {
ledbuffer[c_r] = red;
ledbuffer[c_g] = green;
ledbuffer[c_b] = blue;
}
}
void led_flush(void)
{
uint8_t channel;
for (channel=0; channel<NUM_LED1642GW_CHANNELS-1; channel++) {
write_no_command(ledbuffer[channel+0]);
write_no_command(ledbuffer[channel+NUM_LED1642GW_CHANNELS]);
write_data_latch(ledbuffer[channel+(2*NUM_LED1642GW_CHANNELS)]);
}
write_no_command(ledbuffer[NUM_LED1642GW_CHANNELS-1]);
write_no_command(ledbuffer[(2*NUM_LED1642GW_CHANNELS)-1]);
write_global_latch(ledbuffer[(3*NUM_LED1642GW_CHANNELS)-1]);
}
void led_set_channel(uint8_t channel, uint16_t value)
{
if (channel < NUM_LED_CHANNELS) {
ledbuffer[channel] = value;
}
}
void led_clear(void)
{
memset(ledbuffer, 0x00, sizeof(ledbuffer));
led_flush();
}