--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hello-lkm.c Sat Apr 05 00:37:32 2014 +0300
@@ -0,0 +1,241 @@
+/*
+ * Control the JY-LKM1638 LED display module.
+ */
+
+#include <avr/io.h>
+
+#include "stdlib.h"
+
+// XXX
+#include "timer.c"
+
+#define LKM_DDR DDRC
+#define LKM_PORT PORTC
+#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 = 0b00000010,
+ LKM_DATA_READ = 0b00000000,
+
+ 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_DOT = 0b10000000,
+};
+
+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_start ()
+{
+ // clock low
+ cbi(&LKM_PORT, LKM_CLK);
+
+ // data out
+ sbi(&LKM_DDR, LKM_DIO);
+
+ // select on: low
+ cbi(&LKM_PORT, LKM_STB);
+}
+
+/*
+ * Write out one byte
+ */
+void lkm_write (byte b)
+{
+ char i;
+
+ for (i = 0; i < 8; i++) {
+ // low
+ cbi(&LKM_PORT, LKM_CLK);
+
+ // set output
+ if (b & 1)
+ sbi(&LKM_PORT, LKM_DIO);
+ else
+ cbi(&LKM_PORT, LKM_DIO);
+
+ // clock high
+ sbi(&LKM_PORT, LKM_CLK);
+
+ // next bit
+ b >>= 1;
+ }
+}
+
+/*
+ * 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_start();
+ lkm_write(cmd);
+ lkm_end();
+}
+
+void lkm_cmd1 (byte cmd, byte arg)
+{
+ lkm_start();
+ 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.
+ */
+static void lkm_display_blank ()
+{
+ char i;
+
+ lkm_cmd(LKM_CMD_DATA
+ | LKM_DATA_WRITE
+ | LKM_DATA_ADDR_AUTO
+ | LKM_DATA_TEST_NORMAL
+ );
+
+ // write out all 16 bytes of 0x00
+ lkm_start();
+ 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_WRITE
+ | LKM_DATA_ADDR_AUTO
+ | LKM_DATA_TEST_NORMAL
+ );
+ lkm_cmd1(LKM_CMD_ADDRESS | ((display * 2 + 0) & 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]);
+}
+
+/*
+ * Set 16-bit hexadecimal output on displays 4..7
+ */
+void lkm_display_hex16 (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));
+}
+
+// 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_display_blank();
+ lkm_control(LKM_CONTROL_DISPLAY_ON, LKM_CONTROL_INTENSITY_MAX);
+
+ // start
+ unsigned short i = 0;
+ unsigned short timeout = 8000;
+
+ while (true) {
+ lkm_display_hex16(i++);
+
+ timer_sleep(timeout);
+ }
+}