src/hello-lkm.c
changeset 89 1b3cea759eff
parent 88 c923295ee520
child 90 13c2deb919d1
--- a/src/hello-lkm.c	Mon Jun 02 18:27:08 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,484 +0,0 @@
-/*
- * Control the JY-LKM1638 LED display module.
- */
-
-#include <avr/io.h>
-#include <util/delay.h>
-
-#include "stdlib.h"
-
-// XXX
-#include "timer.c"
-
-#define LKM_DDR     DDRC
-#define LKM_PORT    PORTC
-#define LKM_PIN     PINC
-#define LKM_CLK     0
-#define LKM_DIO     1
-#define LKM_STB     2
-
-enum lkm_cmd {
-    LKM_CMD_DATA    = 0b01000000,
-    LKM_CMD_CONTROL = 0b10000000,
-    LKM_CMD_ADDRESS = 0b11000000,
-
-    LKM_DATA_WRITE          = 0b00000000,
-    LKM_DATA_READ           = 0b00000010,
-
-    LKM_DATA_ADDR_AUTO      = 0b00000000,
-    LKM_DATA_ADDR_FIXED     = 0b00000100,
-
-    LKM_DATA_TEST_NORMAL    = 0b00000000,
-    LKM_DATA_TEST_TEST      = 0b00001000,
-
-    LKM_ADDRESS             = 0b00001111,
-    
-    LKM_CONTROL_INTENSITY       = 0b00000111,
-    LKM_CONTROL_INTENSITY_MIN   = 0b00000000,
-    LKM_CONTROL_INTENSITY_MAX   = 0b00000111,
-
-    LKM_CONTROL_DISPLAY_OFF = 0b00000000,
-    LKM_CONTROL_DISPLAY_ON  = 0b00001000,
-};
-
-static const uint8_t LKM_DISPLAY_FONT[] = {
-    0b00111111,	// 0
-    0b00000110,	// 1
-    0b01011011,	// 2
-    0b01001111,	// 3
-    0b01100110,	// 4
-    0b01101101,	// 5
-    0b01111101,	// 6
-    0b00000111,	// 7
-    0b01111111,	// 8
-    0b01100111,	// 9
-    0b01110111,	// A
-    0b01111100,	// B
-    0b00111001,	// C
-    0b01011110,	// D
-    0b01111001,	// E
-    0b01110001,	// F
-};
-
-enum {
-    LKM_DISPLAY_DECIMAL = 0b10000000,
-};
-
-/*
- * XXX: RED/GREEN somehow swapped vs reference; bug in our write code?
- */
-enum {
-    LKM_LED_OFF     = 0b00,
-    LKM_LED_GREEN   = 0b01,
-    LKM_LED_RED     = 0b10,
-    LKM_LED_ORANGE  = 0b11,
-};
-
-/*
- * Button bitfields.
- *
- * The JY-LKM1638 uses K3
- */
-enum {
-    LKM_BUTTON_K1L  = 0b00000100,
-    LKM_BUTTON_K2L  = 0b00000010,
-    LKM_BUTTON_K3L  = 0b00000001,
-    
-    LKM_BUTTON_K1H  = 0b01000000,
-    LKM_BUTTON_K2H  = 0b00100000,
-    LKM_BUTTON_K3H  = 0b00010000,
-};
-
-void lkm_init ()
-{
-    // strobe off: high output
-    // XXX: should use an external pull-up resistor?
-    sbi(&LKM_PORT, LKM_STB);
-    sbi(&LKM_DDR, LKM_STB);
-
-    // clock low
-    sbi(&LKM_DDR, LKM_CLK);
-    cbi(&LKM_PORT, LKM_CLK);
-
-    // data tri-state
-    cbi(&LKM_DDR, LKM_DIO);
-    cbi(&LKM_DDR, LKM_DIO);
-}
-
-/*
- * Select the LKM for write.
- */
-void lkm_out ()
-{
-    // clock low
-    cbi(&LKM_PORT, LKM_CLK);
-
-    // data out
-    sbi(&LKM_DDR, LKM_DIO);
-
-    // select on: low
-    cbi(&LKM_PORT, LKM_STB);
-}
-
-/*
- * Select the LKM for read.
- */
-void lkm_in ()
-{
-    // data in
-    cbi(&LKM_DDR, LKM_DIO);
-    cbi(&LKM_PORT, LKM_DIO);
-
-    // select on: low
-    cbi(&LKM_PORT, LKM_STB);
-
-    // clock high
-    sbi(&LKM_PORT, LKM_CLK);
-
-    // pause
-    _delay_us(1);
-}
-
-/*
- * Write out one byte
- */
-void lkm_write (byte b)
-{
-    char i;
-
-    for (i = 0; i < 8; i++) {
-        // clock read: low
-        cbi(&LKM_PORT, LKM_CLK);
-
-        // set output
-        if (b & 1)
-            sbi(&LKM_PORT, LKM_DIO);
-        else 
-            cbi(&LKM_PORT, LKM_DIO);
-        
-        // clock write: high
-        sbi(&LKM_PORT, LKM_CLK);
-        
-        // next bit
-        b >>= 1;
-    }
-}
-
-/*
- * Read in one byte.
- */
-byte lkm_read ()
-{
-    byte b = 0;
-    char i;
-
-    // XXX: this loop is timing-critical; we must allow the signal to settle betwen clocks
-    for (i = 0; i < 8; i++) {
-        // next bit
-        b >>= 1;
-
-        // clock read: low
-        cbi(&LKM_PORT, LKM_CLK);
-    
-        // pause
-        _delay_us(1);
-
-        // read input
-        if (tbi(&LKM_PIN, LKM_DIO))
-            b |= 0x80;
-        
-        // pause
-        _delay_us(1);
-
-        // clock write: high
-        sbi(&LKM_PORT, LKM_CLK);
-        
-        // pause
-        _delay_us(1);
-    }
-
-    return b;
-}
-
-/*
- * End command.
- */
-void lkm_end ()
-{
-    // select off: high
-    sbi(&LKM_PORT, LKM_STB);
-
-    // tristate data
-    cbi(&LKM_DDR, LKM_DIO);
-}
-
-void lkm_cmd (byte cmd)
-{
-    lkm_out();
-    lkm_write(cmd);
-    lkm_end();
-}
-
-void lkm_cmd1 (byte cmd, byte arg)
-{
-    lkm_out();
-    lkm_write(cmd);
-    lkm_write(arg);
-    lkm_end();
-}
-
-static inline void lkm_control (byte display, byte intensity)
-{
-    lkm_cmd(LKM_CMD_CONTROL
-        |   (display ? LKM_CONTROL_DISPLAY_ON : LKM_CONTROL_DISPLAY_OFF)
-        |   (intensity & LKM_CONTROL_INTENSITY)
-    );
-}
-
-/*
- * Blank display/LEDs
- */
-static void lkm_clear ()
-{
-    char i;
-
-    lkm_cmd(LKM_CMD_DATA
-        |   LKM_DATA_TEST_NORMAL
-        |   LKM_DATA_ADDR_AUTO
-        |   LKM_DATA_WRITE
-    );
-    
-    // write out all 16 bytes of 0x00
-    lkm_out();
-    lkm_write(LKM_CMD_ADDRESS | (0x0) & LKM_ADDRESS);
-    for (i = 0; i < 16; i++) {
-        lkm_write(0x00);
-    }
-    lkm_end();
-
-}
-
-/*
- * Set raw output mask for given display 0..7
- */
-static inline void lkm_display (byte display, byte value)
-{
-    lkm_cmd(LKM_CMD_DATA
-        |   LKM_DATA_TEST_NORMAL
-        |   LKM_DATA_ADDR_AUTO
-        |   LKM_DATA_WRITE
-    );
-    lkm_cmd1(LKM_CMD_ADDRESS | ((display * 2 + 0) & LKM_ADDRESS),
-        value
-    );
-}
-
-/*
- * Set raw output mask for given led 0..7
- */
-static inline void lkm_led (byte led, byte value)
-{
-    lkm_cmd(LKM_CMD_DATA
-        |   LKM_DATA_TEST_NORMAL
-        |   LKM_DATA_ADDR_AUTO
-        |   LKM_DATA_WRITE
-    );
-    lkm_cmd1(LKM_CMD_ADDRESS | ((led * 2 + 1) & LKM_ADDRESS),
-        value
-    );
-}
-
-/*
- * Set 4-bit hexadecimal output for given display 0..7
- */
-static inline void lkm_display_hex (byte display, byte hex)
-{
-    lkm_display(display, LKM_DISPLAY_FONT[hex]);
-}
-
-static inline void lkm_display_dec (byte display, byte dec, byte decimal)
-{
-    byte raw;
-
-    if (dec < 10)
-        raw = LKM_DISPLAY_FONT[dec];
-    else
-        raw = 0x00;
-
-    if (decimal)
-        raw |= LKM_DISPLAY_DECIMAL;
-
-    lkm_display(display, raw);
-}
-
-/*
- * Read the 8-bit key states
- */
-byte lkm_buttons ()
-{
-    byte k3 = 0;
-    char i;
-
-    lkm_out();
-    lkm_write(LKM_CMD_DATA
-        |   LKM_DATA_TEST_NORMAL
-        |   LKM_DATA_ADDR_AUTO
-        |   LKM_DATA_READ
-    );
-    lkm_in();
-    for (i = 0; i < 4; i++) {
-        /*
-         * The ordering of keys used is weird; it seems to go 04 15 26 37
-         */
-        k3 |= lkm_read() << i;
-        
-        /*
-        k3 >>= 1;
-
-        byte b = lkm_read();
-
-        if (b & LKM_BUTTON_K3L)
-            k3 |= 0b00001000;
-
-        if (b & LKM_BUTTON_K3H)
-            k3 |= 0b10000000;
-        */
-    }
-    lkm_end();
-
-    return k3;
-}
-
-/*
- * Set 8-bit hexadecimal output on displays n..n+1
- */
-void lkm_display_hh (byte display, byte hex)
-{
-    lkm_display_hex(display + 0, ((hex >> 4) & 0xF));
-    lkm_display_hex(display + 1, ((hex >> 0) & 0xF));
-}
-
-/*
- * Set 16-bit hexadecimal output on displays 4..7
- */
-void lkm_display_hhhh (short hex)
-{
-    lkm_display_hex(7, ((hex >> 0) & 0xF));
-    lkm_display_hex(6, ((hex >> 4) & 0xF));
-    lkm_display_hex(5, ((hex >> 8) & 0xF));
-    lkm_display_hex(4, ((hex >> 12) & 0xF));
-}
-
-/*
- * Set 2-digit decimal output on displays n..n+1
- */
-void lkm_display_dd (byte display, byte dec)
-{
-    byte d = dec / 10;
-    byte u = dec % 10;
-
-    byte c = d / 10;
-    d = d % 10;
-
-    lkm_display_dec(display + 0, d, c > 1);
-    lkm_display_dec(display + 1, u, c > 0);
-}
-
-// debug
-#define DEBUG_DDR   DDRB
-#define DEBUG_PORT  PORTB
-#define DEBUG_LED   0
-
-int main (void)
-{
-    // led_init();
-    sbi(&DEBUG_DDR, DEBUG_LED);
-
-    timer_init();
-    lkm_init();
-
-    sei();
-
-    // setup display
-    lkm_clear();
-    lkm_control(LKM_CONTROL_DISPLAY_ON, LKM_CONTROL_INTENSITY_MAX);
-
-/*
-    // test
-    lkm_led(0, LKM_LED_OFF);
-    lkm_led(1, LKM_LED_RED);
-    lkm_led(2, LKM_LED_GREEN);
-    lkm_led(3, LKM_LED_ORANGE);
-
-    return 0;
-*/
-
-    // start
-    byte channels[4] = { };
-    enum channel_state {
-        CHANNEL_IDLE    = 0,
-        CHANNEL_INC,
-        CHANNEL_DEC,
-    } channel_state[4] = { };
-    byte channel_count[4] = { };
-    char c;
-        
-    while (true) {
-        // scan input
-        byte buttons = lkm_buttons();
-        
-        for (c = 0; c < 4; c++) {
-            enum channel_state state = channel_state[c], next;
-            byte count = channel_count[c];
-
-            // decode buttons -> state
-            if (buttons & 0b1) {
-                next = CHANNEL_INC;
-            } else if (buttons & 0b10) {
-                next = CHANNEL_DEC;
-            } else {
-                next = CHANNEL_IDLE;
-            }
-            
-            buttons >>= 2;
-            
-            // feedback
-            if (state == CHANNEL_INC || next == CHANNEL_INC)
-                lkm_led(c * 2 + 0, LKM_LED_GREEN);
-            else if (state == CHANNEL_DEC && next == CHANNEL_DEC)
-                lkm_led(c * 2 + 0, LKM_LED_RED);
-            else
-                lkm_led(c * 2 + 0, LKM_LED_OFF);
-
-            if (state == CHANNEL_DEC || next == CHANNEL_DEC)
-                lkm_led(c * 2 + 1, LKM_LED_RED);
-            else if (state == CHANNEL_INC && next == CHANNEL_INC)
-                lkm_led(c * 2 + 1, LKM_LED_GREEN);
-            else
-                lkm_led(c * 2 + 1, LKM_LED_OFF);
-
-            // counts
-            if ((channel_state[c] = next) != state)
-                channel_count[c] = 0;
-            else
-                count = ++channel_count[c];
-
-            // state transitions
-            if (next == CHANNEL_INC && count > 0) {
-                channels[c] += count;
-            } else if (next == CHANNEL_DEC && count > 0) {
-                channels[c] -= count;
-            } else if (state == CHANNEL_INC && !count) {
-                channels[c] = 0xff;
-            } else if (state == CHANNEL_DEC && !count) {
-                channels[c] = 0x00;
-            }
-
-            lkm_display_hh(c * 2, channels[c]);
-        
-            xbi(&DEBUG_PORT, DEBUG_LED);
-        }
-
-        timer_sleep(8000);
-    }
-}