# HG changeset patch # User Tero Marttila # Date 1396647452 -10800 # Node ID a445e08b63e02168a29730ee94a453613c6452aa # Parent ee412c5be8b1a48b4c8585e739b1b16c86d4cd06 hello-lkm: Control the JY-LKM1638 LED 7-segment display module diff -r ee412c5be8b1 -r a445e08b63e0 Makefile --- a/Makefile Fri Apr 04 13:14:04 2014 +0300 +++ b/Makefile Sat Apr 05 00:37:32 2014 +0300 @@ -1,6 +1,4 @@ -PROG = hello -# console -# dmx +PROG = hello-lkm ELF = build/src/$(PROG).elf HEX = build/src/$(PROG).hex diff -r ee412c5be8b1 -r a445e08b63e0 src/hello-lkm.c --- /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 + +#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); + } +} diff -r ee412c5be8b1 -r a445e08b63e0 src/stdlib.h --- a/src/stdlib.h Fri Apr 04 13:14:04 2014 +0300 +++ b/src/stdlib.h Sat Apr 05 00:37:32 2014 +0300 @@ -1,6 +1,8 @@ #define false 0 #define true 1 +typedef uint8_t byte; + typedef volatile uint8_t ioport_t; static inline ioport_t tbi(ioport_t *port, int bit)