--- 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);
- }
-}