# HG changeset patch # User Tero Marttila # Date 1396651826 -10800 # Node ID 7090f61e5e17d94de993d5c7bf5ecda2fa6ce537 # Parent a445e08b63e02168a29730ee94a453613c6452aa hello-lkm: buttons diff -r a445e08b63e0 -r 7090f61e5e17 src/hello-lkm.c --- a/src/hello-lkm.c Sat Apr 05 00:37:32 2014 +0300 +++ b/src/hello-lkm.c Sat Apr 05 01:50:26 2014 +0300 @@ -3,6 +3,7 @@ */ #include +#include #include "stdlib.h" @@ -11,6 +12,7 @@ #define LKM_DDR DDRC #define LKM_PORT PORTC +#define LKM_PIN PINC #define LKM_CLK 0 #define LKM_DIO 1 #define LKM_STB 2 @@ -20,8 +22,8 @@ LKM_CMD_CONTROL = 0b10000000, LKM_CMD_ADDRESS = 0b11000000, - LKM_DATA_WRITE = 0b00000010, - LKM_DATA_READ = 0b00000000, + LKM_DATA_WRITE = 0b00000000, + LKM_DATA_READ = 0b00000010, LKM_DATA_ADDR_AUTO = 0b00000000, LKM_DATA_ADDR_FIXED = 0b00000100, @@ -62,6 +64,28 @@ LKM_DISPLAY_DOT = 0b10000000, }; +enum { + LKM_LED_OFF = 0b00, + LKM_LED_RED = 0b01, + LKM_LED_GREEN = 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 @@ -81,7 +105,7 @@ /* * Select the LKM for write. */ -void lkm_start () +void lkm_out () { // clock low cbi(&LKM_PORT, LKM_CLK); @@ -94,6 +118,25 @@ } /* + * 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) @@ -101,7 +144,7 @@ char i; for (i = 0; i < 8; i++) { - // low + // clock read: low cbi(&LKM_PORT, LKM_CLK); // set output @@ -110,7 +153,7 @@ else cbi(&LKM_PORT, LKM_DIO); - // clock high + // clock write: high sbi(&LKM_PORT, LKM_CLK); // next bit @@ -119,6 +162,42 @@ } /* + * 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 () @@ -132,14 +211,14 @@ void lkm_cmd (byte cmd) { - lkm_start(); + lkm_out(); lkm_write(cmd); lkm_end(); } void lkm_cmd1 (byte cmd, byte arg) { - lkm_start(); + lkm_out(); lkm_write(cmd); lkm_write(arg); lkm_end(); @@ -154,20 +233,20 @@ } /* - * Blank display. + * Blank display/LEDs */ -static void lkm_display_blank () +static void lkm_clear () { char i; lkm_cmd(LKM_CMD_DATA + | LKM_DATA_TEST_NORMAL + | LKM_DATA_ADDR_AUTO | LKM_DATA_WRITE - | LKM_DATA_ADDR_AUTO - | LKM_DATA_TEST_NORMAL ); // write out all 16 bytes of 0x00 - lkm_start(); + lkm_out(); lkm_write(LKM_CMD_ADDRESS | (0x0) & LKM_ADDRESS); for (i = 0; i < 16; i++) { lkm_write(0x00); @@ -182,9 +261,9 @@ 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_DATA_ADDR_AUTO - | LKM_DATA_TEST_NORMAL ); lkm_cmd1(LKM_CMD_ADDRESS | ((display * 2 + 0) & LKM_ADDRESS), value @@ -192,6 +271,21 @@ } /* + * 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) @@ -200,6 +294,44 @@ } /* + * 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 16-bit hexadecimal output on displays 4..7 */ void lkm_display_hex16 (short hex) @@ -226,16 +358,32 @@ sei(); // setup display - lkm_display_blank(); + lkm_clear(); lkm_control(LKM_CONTROL_DISPLAY_ON, LKM_CONTROL_INTENSITY_MAX); // start - unsigned short i = 0; - unsigned short timeout = 8000; + byte state[8] = { }; + char i; while (true) { - lkm_display_hex16(i++); + // scan input + byte buttons = lkm_buttons(); + + for (i = 0; i < 8; i++) { + if (!(buttons & (1 << i))) { + continue; + } else if (state[i] >= 0xF) { + state[i] = 0; + } else { + state[i]++; + } - timer_sleep(timeout); + lkm_display_hex(i, state[i]); + lkm_led(i, state[i]); + + xbi(&DEBUG_PORT, DEBUG_LED); + } + + timer_sleep(16000); } }