src/hello-lkm.c
changeset 59 7090f61e5e17
parent 58 a445e08b63e0
child 60 b9648067e9d7
equal deleted inserted replaced
58:a445e08b63e0 59:7090f61e5e17
     1 /*
     1 /*
     2  * Control the JY-LKM1638 LED display module.
     2  * Control the JY-LKM1638 LED display module.
     3  */
     3  */
     4 
     4 
     5 #include <avr/io.h>
     5 #include <avr/io.h>
       
     6 #include <util/delay.h>
     6 
     7 
     7 #include "stdlib.h"
     8 #include "stdlib.h"
     8 
     9 
     9 // XXX
    10 // XXX
    10 #include "timer.c"
    11 #include "timer.c"
    11 
    12 
    12 #define LKM_DDR     DDRC
    13 #define LKM_DDR     DDRC
    13 #define LKM_PORT    PORTC
    14 #define LKM_PORT    PORTC
       
    15 #define LKM_PIN     PINC
    14 #define LKM_CLK     0
    16 #define LKM_CLK     0
    15 #define LKM_DIO     1
    17 #define LKM_DIO     1
    16 #define LKM_STB     2
    18 #define LKM_STB     2
    17 
    19 
    18 enum lkm_cmd {
    20 enum lkm_cmd {
    19     LKM_CMD_DATA    = 0b01000000,
    21     LKM_CMD_DATA    = 0b01000000,
    20     LKM_CMD_CONTROL = 0b10000000,
    22     LKM_CMD_CONTROL = 0b10000000,
    21     LKM_CMD_ADDRESS = 0b11000000,
    23     LKM_CMD_ADDRESS = 0b11000000,
    22 
    24 
    23     LKM_DATA_WRITE          = 0b00000010,
    25     LKM_DATA_WRITE          = 0b00000000,
    24     LKM_DATA_READ           = 0b00000000,
    26     LKM_DATA_READ           = 0b00000010,
    25 
    27 
    26     LKM_DATA_ADDR_AUTO      = 0b00000000,
    28     LKM_DATA_ADDR_AUTO      = 0b00000000,
    27     LKM_DATA_ADDR_FIXED     = 0b00000100,
    29     LKM_DATA_ADDR_FIXED     = 0b00000100,
    28 
    30 
    29     LKM_DATA_TEST_NORMAL    = 0b00000000,
    31     LKM_DATA_TEST_NORMAL    = 0b00000000,
    60 
    62 
    61 enum {
    63 enum {
    62     LKM_DISPLAY_DOT     = 0b10000000,
    64     LKM_DISPLAY_DOT     = 0b10000000,
    63 };
    65 };
    64 
    66 
       
    67 enum {
       
    68     LKM_LED_OFF     = 0b00,
       
    69     LKM_LED_RED     = 0b01,
       
    70     LKM_LED_GREEN   = 0b10,
       
    71     LKM_LED_ORANGE  = 0b11,
       
    72 };
       
    73 
       
    74 /*
       
    75  * Button bitfields.
       
    76  *
       
    77  * The JY-LKM1638 uses K3
       
    78  */
       
    79 enum {
       
    80     LKM_BUTTON_K1L  = 0b00000100,
       
    81     LKM_BUTTON_K2L  = 0b00000010,
       
    82     LKM_BUTTON_K3L  = 0b00000001,
       
    83     
       
    84     LKM_BUTTON_K1H  = 0b01000000,
       
    85     LKM_BUTTON_K2H  = 0b00100000,
       
    86     LKM_BUTTON_K3H  = 0b00010000,
       
    87 };
       
    88 
    65 void lkm_init ()
    89 void lkm_init ()
    66 {
    90 {
    67     // strobe off: high output
    91     // strobe off: high output
    68     // XXX: should use an external pull-up resistor?
    92     // XXX: should use an external pull-up resistor?
    69     sbi(&LKM_PORT, LKM_STB);
    93     sbi(&LKM_PORT, LKM_STB);
    79 }
   103 }
    80 
   104 
    81 /*
   105 /*
    82  * Select the LKM for write.
   106  * Select the LKM for write.
    83  */
   107  */
    84 void lkm_start ()
   108 void lkm_out ()
    85 {
   109 {
    86     // clock low
   110     // clock low
    87     cbi(&LKM_PORT, LKM_CLK);
   111     cbi(&LKM_PORT, LKM_CLK);
    88 
   112 
    89     // data out
   113     // data out
    92     // select on: low
   116     // select on: low
    93     cbi(&LKM_PORT, LKM_STB);
   117     cbi(&LKM_PORT, LKM_STB);
    94 }
   118 }
    95 
   119 
    96 /*
   120 /*
       
   121  * Select the LKM for read.
       
   122  */
       
   123 void lkm_in ()
       
   124 {
       
   125     // data in
       
   126     cbi(&LKM_DDR, LKM_DIO);
       
   127     cbi(&LKM_PORT, LKM_DIO);
       
   128 
       
   129     // select on: low
       
   130     cbi(&LKM_PORT, LKM_STB);
       
   131 
       
   132     // clock high
       
   133     sbi(&LKM_PORT, LKM_CLK);
       
   134 
       
   135     // pause
       
   136     _delay_us(1);
       
   137 }
       
   138 
       
   139 /*
    97  * Write out one byte
   140  * Write out one byte
    98  */
   141  */
    99 void lkm_write (byte b)
   142 void lkm_write (byte b)
   100 {
   143 {
   101     char i;
   144     char i;
   102 
   145 
   103     for (i = 0; i < 8; i++) {
   146     for (i = 0; i < 8; i++) {
   104         // low
   147         // clock read: low
   105         cbi(&LKM_PORT, LKM_CLK);
   148         cbi(&LKM_PORT, LKM_CLK);
   106 
   149 
   107         // set output
   150         // set output
   108         if (b & 1)
   151         if (b & 1)
   109             sbi(&LKM_PORT, LKM_DIO);
   152             sbi(&LKM_PORT, LKM_DIO);
   110         else 
   153         else 
   111             cbi(&LKM_PORT, LKM_DIO);
   154             cbi(&LKM_PORT, LKM_DIO);
   112         
   155         
   113         // clock high
   156         // clock write: high
   114         sbi(&LKM_PORT, LKM_CLK);
   157         sbi(&LKM_PORT, LKM_CLK);
   115         
   158         
   116         // next bit
   159         // next bit
   117         b >>= 1;
   160         b >>= 1;
   118     }
   161     }
   119 }
   162 }
   120 
   163 
   121 /*
   164 /*
       
   165  * Read in one byte.
       
   166  */
       
   167 byte lkm_read ()
       
   168 {
       
   169     byte b = 0;
       
   170     char i;
       
   171 
       
   172     // XXX: this loop is timing-critical; we must allow the signal to settle betwen clocks
       
   173     for (i = 0; i < 8; i++) {
       
   174         // next bit
       
   175         b >>= 1;
       
   176 
       
   177         // clock read: low
       
   178         cbi(&LKM_PORT, LKM_CLK);
       
   179     
       
   180         // pause
       
   181         _delay_us(1);
       
   182 
       
   183         // read input
       
   184         if (tbi(&LKM_PIN, LKM_DIO))
       
   185             b |= 0x80;
       
   186         
       
   187         // pause
       
   188         _delay_us(1);
       
   189 
       
   190         // clock write: high
       
   191         sbi(&LKM_PORT, LKM_CLK);
       
   192         
       
   193         // pause
       
   194         _delay_us(1);
       
   195     }
       
   196 
       
   197     return b;
       
   198 }
       
   199 
       
   200 /*
   122  * End command.
   201  * End command.
   123  */
   202  */
   124 void lkm_end ()
   203 void lkm_end ()
   125 {
   204 {
   126     // select off: high
   205     // select off: high
   130     cbi(&LKM_DDR, LKM_DIO);
   209     cbi(&LKM_DDR, LKM_DIO);
   131 }
   210 }
   132 
   211 
   133 void lkm_cmd (byte cmd)
   212 void lkm_cmd (byte cmd)
   134 {
   213 {
   135     lkm_start();
   214     lkm_out();
   136     lkm_write(cmd);
   215     lkm_write(cmd);
   137     lkm_end();
   216     lkm_end();
   138 }
   217 }
   139 
   218 
   140 void lkm_cmd1 (byte cmd, byte arg)
   219 void lkm_cmd1 (byte cmd, byte arg)
   141 {
   220 {
   142     lkm_start();
   221     lkm_out();
   143     lkm_write(cmd);
   222     lkm_write(cmd);
   144     lkm_write(arg);
   223     lkm_write(arg);
   145     lkm_end();
   224     lkm_end();
   146 }
   225 }
   147 
   226 
   152         |   (intensity & LKM_CONTROL_INTENSITY)
   231         |   (intensity & LKM_CONTROL_INTENSITY)
   153     );
   232     );
   154 }
   233 }
   155 
   234 
   156 /*
   235 /*
   157  * Blank display.
   236  * Blank display/LEDs
   158  */
   237  */
   159 static void lkm_display_blank ()
   238 static void lkm_clear ()
   160 {
   239 {
   161     char i;
   240     char i;
   162 
   241 
   163     lkm_cmd(LKM_CMD_DATA
   242     lkm_cmd(LKM_CMD_DATA
       
   243         |   LKM_DATA_TEST_NORMAL
       
   244         |   LKM_DATA_ADDR_AUTO
   164         |   LKM_DATA_WRITE
   245         |   LKM_DATA_WRITE
   165         |   LKM_DATA_ADDR_AUTO
       
   166         |   LKM_DATA_TEST_NORMAL
       
   167     );
   246     );
   168     
   247     
   169     // write out all 16 bytes of 0x00
   248     // write out all 16 bytes of 0x00
   170     lkm_start();
   249     lkm_out();
   171     lkm_write(LKM_CMD_ADDRESS | (0x0) & LKM_ADDRESS);
   250     lkm_write(LKM_CMD_ADDRESS | (0x0) & LKM_ADDRESS);
   172     for (i = 0; i < 16; i++) {
   251     for (i = 0; i < 16; i++) {
   173         lkm_write(0x00);
   252         lkm_write(0x00);
   174     }
   253     }
   175     lkm_end();
   254     lkm_end();
   180  * Set raw output mask for given display 0..7
   259  * Set raw output mask for given display 0..7
   181  */
   260  */
   182 static inline void lkm_display (byte display, byte value)
   261 static inline void lkm_display (byte display, byte value)
   183 {
   262 {
   184     lkm_cmd(LKM_CMD_DATA
   263     lkm_cmd(LKM_CMD_DATA
       
   264         |   LKM_DATA_TEST_NORMAL
       
   265         |   LKM_DATA_ADDR_AUTO
   185         |   LKM_DATA_WRITE
   266         |   LKM_DATA_WRITE
   186         |   LKM_DATA_ADDR_AUTO
       
   187         |   LKM_DATA_TEST_NORMAL
       
   188     );
   267     );
   189     lkm_cmd1(LKM_CMD_ADDRESS | ((display * 2 + 0) & LKM_ADDRESS),
   268     lkm_cmd1(LKM_CMD_ADDRESS | ((display * 2 + 0) & LKM_ADDRESS),
   190         value
   269         value
   191     );
   270     );
   192 }
   271 }
   193 
   272 
   194 /*
   273 /*
       
   274  * Set raw output mask for given led 0..7
       
   275  */
       
   276 static inline void lkm_led (byte led, byte value)
       
   277 {
       
   278     lkm_cmd(LKM_CMD_DATA
       
   279         |   LKM_DATA_TEST_NORMAL
       
   280         |   LKM_DATA_ADDR_AUTO
       
   281         |   LKM_DATA_WRITE
       
   282     );
       
   283     lkm_cmd1(LKM_CMD_ADDRESS | ((led * 2 + 1) & LKM_ADDRESS),
       
   284         value
       
   285     );
       
   286 }
       
   287 
       
   288 /*
   195  * Set 4-bit hexadecimal output for given display 0..7
   289  * Set 4-bit hexadecimal output for given display 0..7
   196  */
   290  */
   197 static inline void lkm_display_hex (byte display, byte hex)
   291 static inline void lkm_display_hex (byte display, byte hex)
   198 {
   292 {
   199     lkm_display(display, LKM_DISPLAY_FONT[hex]);
   293     lkm_display(display, LKM_DISPLAY_FONT[hex]);
       
   294 }
       
   295 
       
   296 /*
       
   297  * Read the 8-bit key states
       
   298  */
       
   299 byte lkm_buttons ()
       
   300 {
       
   301     byte k3 = 0;
       
   302     char i;
       
   303 
       
   304     lkm_out();
       
   305     lkm_write(LKM_CMD_DATA
       
   306         |   LKM_DATA_TEST_NORMAL
       
   307         |   LKM_DATA_ADDR_AUTO
       
   308         |   LKM_DATA_READ
       
   309     );
       
   310     lkm_in();
       
   311     for (i = 0; i < 4; i++) {
       
   312         /*
       
   313          * The ordering of keys used is weird; it seems to go 04 15 26 37
       
   314          */
       
   315         k3 |= lkm_read() << i;
       
   316         
       
   317         /*
       
   318         k3 >>= 1;
       
   319 
       
   320         byte b = lkm_read();
       
   321 
       
   322         if (b & LKM_BUTTON_K3L)
       
   323             k3 |= 0b00001000;
       
   324 
       
   325         if (b & LKM_BUTTON_K3H)
       
   326             k3 |= 0b10000000;
       
   327         */
       
   328     }
       
   329     lkm_end();
       
   330 
       
   331     return k3;
   200 }
   332 }
   201 
   333 
   202 /*
   334 /*
   203  * Set 16-bit hexadecimal output on displays 4..7
   335  * Set 16-bit hexadecimal output on displays 4..7
   204  */
   336  */
   224     lkm_init();
   356     lkm_init();
   225 
   357 
   226     sei();
   358     sei();
   227 
   359 
   228     // setup display
   360     // setup display
   229     lkm_display_blank();
   361     lkm_clear();
   230     lkm_control(LKM_CONTROL_DISPLAY_ON, LKM_CONTROL_INTENSITY_MAX);
   362     lkm_control(LKM_CONTROL_DISPLAY_ON, LKM_CONTROL_INTENSITY_MAX);
   231 
   363 
   232     // start
   364     // start
   233     unsigned short i = 0;
   365     byte state[8] = { };
   234     unsigned short timeout = 8000;
   366     char i;
   235         
   367         
   236     while (true) {
   368     while (true) {
   237         lkm_display_hex16(i++);
   369         // scan input
   238 
   370         byte buttons = lkm_buttons();
   239         timer_sleep(timeout);
   371         
   240     }
   372         for (i = 0; i < 8; i++) {
   241 }
   373             if (!(buttons & (1 << i))) {
       
   374                 continue;
       
   375             } else if (state[i] >= 0xF) {
       
   376                 state[i] = 0;
       
   377             } else {
       
   378                 state[i]++;
       
   379             }
       
   380 
       
   381             lkm_display_hex(i, state[i]);
       
   382             lkm_led(i, state[i]);
       
   383             
       
   384             xbi(&DEBUG_PORT, DEBUG_LED);
       
   385         }
       
   386 
       
   387         timer_sleep(16000);
       
   388     }
       
   389 }