2014-03-02 07:18:48 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
* "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
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2014-03-03 05:01:36 +01:00
|
|
|
/*
|
|
|
|
* This module tries to control 15 RGB-LEDs
|
|
|
|
* connected to three daisy-chained
|
|
|
|
* LED1642GW-ICs from STM.
|
|
|
|
*/
|
|
|
|
|
2014-03-02 07:18:48 +01:00
|
|
|
#include "ledcontroller.h"
|
|
|
|
#include <string.h>
|
2014-03-12 23:46:14 +01:00
|
|
|
#include <util/delay.h>
|
2014-03-02 07:18:48 +01:00
|
|
|
|
|
|
|
|
|
|
|
#define NUM_LED1642GW_ICs (3)
|
|
|
|
#define NUM_LED1642GW_CHANNELS (16)
|
2014-03-12 23:46:14 +01:00
|
|
|
#define NUM_LED_CHANNELS (NUM_LED1642GW_CHANNELS*NUM_LED1642GW_ICs)
|
2014-03-02 07:18:48 +01:00
|
|
|
|
2014-03-12 23:46:14 +01:00
|
|
|
static uint16_t ledbuffer[NUM_LED_CHANNELS];
|
2014-03-02 07:18:48 +01:00
|
|
|
|
2014-03-03 05:01:36 +01:00
|
|
|
static int8_t map_lednum_to_channels(uint8_t lednum, uint8_t *channel_r, uint8_t *channel_g, uint8_t *channel_b)
|
2014-03-02 07:18:48 +01:00
|
|
|
{
|
|
|
|
uint8_t ret;
|
|
|
|
|
|
|
|
if (lednum < 15) {
|
|
|
|
*channel_r = 3*lednum;
|
|
|
|
*channel_g = 3*lednum+1;
|
|
|
|
*channel_b = 3*lednum+2;
|
|
|
|
if ( lednum >= 10 ) {
|
|
|
|
*channel_r += 2;
|
|
|
|
*channel_g += 2;
|
|
|
|
*channel_b += 2;
|
|
|
|
}
|
|
|
|
else if ( lednum >= 5 ) {
|
|
|
|
*channel_r += 1;
|
|
|
|
*channel_g += 1;
|
|
|
|
*channel_b += 1;
|
|
|
|
}
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-03-12 23:46:14 +01:00
|
|
|
|
|
|
|
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);
|
2014-03-02 07:18:48 +01:00
|
|
|
mask >>= 1;
|
|
|
|
}
|
2014-03-12 23:46:14 +01:00
|
|
|
|
|
|
|
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);
|
2014-03-02 07:18:48 +01:00
|
|
|
}
|
|
|
|
|
2014-03-12 23:46:14 +01:00
|
|
|
|
2014-03-02 07:18:48 +01:00
|
|
|
static void write_data_latch(uint16_t data)
|
|
|
|
{
|
|
|
|
write_data(data, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void write_global_latch(uint16_t data)
|
|
|
|
{
|
|
|
|
write_data(data, 6);
|
|
|
|
}
|
|
|
|
|
2014-03-13 01:33:13 +01:00
|
|
|
static void write_no_command(uint16_t data)
|
|
|
|
{
|
|
|
|
write_data(data, 0);
|
|
|
|
}
|
|
|
|
|
2014-03-02 07:18:48 +01:00
|
|
|
|
2014-03-12 21:12:16 +01:00
|
|
|
void ledcontroller_turn_all_on(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
write_data(0xffff, 2);
|
2014-03-12 23:46:14 +01:00
|
|
|
_delay_us(10);
|
2014-03-12 21:12:16 +01:00
|
|
|
write_data(0xffff, 2);
|
2014-03-12 23:46:14 +01:00
|
|
|
_delay_us(10);
|
2014-03-12 21:12:16 +01:00
|
|
|
write_data(0xffff, 2);
|
2014-03-12 23:46:14 +01:00
|
|
|
_delay_us(10);
|
2014-03-12 21:12:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ledcontroller_turn_all_off(void)
|
|
|
|
{
|
|
|
|
|
2014-03-12 23:46:14 +01:00
|
|
|
write_data(0x0000, 2);
|
|
|
|
_delay_us(10);
|
|
|
|
write_data(0x0000, 2);
|
|
|
|
_delay_us(10);
|
|
|
|
write_data(0x0000, 2);
|
|
|
|
_delay_us(10);
|
2014-03-12 21:12:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-02 07:18:48 +01:00
|
|
|
void ledcontroller_init(void)
|
|
|
|
{
|
|
|
|
|
2014-03-03 05:01:36 +01:00
|
|
|
PORTC &= ~(1<<PC3); // SCK
|
|
|
|
PORTC &= ~(1<<PC4); // DATA
|
|
|
|
PORTC &= ~(1<<PC2); // LE
|
2014-03-02 07:18:48 +01:00
|
|
|
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;
|
|
|
|
|
2014-03-03 05:01:36 +01:00
|
|
|
if ( map_lednum_to_channels(lednum, &c_r, &c_g, &c_b) > 0 ) {
|
2014-03-02 07:18:48 +01:00
|
|
|
ledbuffer[c_r] = red;
|
|
|
|
ledbuffer[c_g] = green;
|
|
|
|
ledbuffer[c_b] = blue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-13 01:33:13 +01:00
|
|
|
void led_flush(void)
|
|
|
|
{
|
|
|
|
uint8_t channel;
|
|
|
|
for (channel=0; channel<NUM_LED1642GW_CHANNELS-1; channel++) {
|
2014-03-13 02:05:24 +01:00
|
|
|
write_no_command(ledbuffer[channel+0]);
|
|
|
|
write_no_command(ledbuffer[channel+16]);
|
|
|
|
write_data_latch(ledbuffer[channel+32]);
|
2014-03-13 01:33:13 +01:00
|
|
|
}
|
2014-03-13 02:05:24 +01:00
|
|
|
write_no_command(ledbuffer[NUM_LED1642GW_CHANNELS-3]);
|
|
|
|
write_no_command(ledbuffer[NUM_LED1642GW_CHANNELS-2]);
|
|
|
|
write_global_latch(ledbuffer[NUM_LED1642GW_CHANNELS-1]);
|
2014-03-13 01:33:13 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ledcontroller_set_channel(uint8_t channel, uint16_t value)
|
|
|
|
{
|
|
|
|
if (channel < NUM_LED_CHANNELS) {
|
|
|
|
ledbuffer[channel] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-03-02 07:18:48 +01:00
|
|
|
|