lcd_32122a_avr.c
Go to the documentation of this file.00001
00042 #include "lcd_32122a_avr.h"
00043 #include <gfx/gfx.h>
00044 #include <drv/timer.h>
00045
00046 #include <cpu/irq.h>
00047 #include <cpu/types.h>
00048 #include <hw.h>
00049 #include <cfg/macros.h>
00050 #include <cfg/debug.h>
00051
00052 #include <avr/io.h>
00053 #include <stdbool.h>
00054 #include <inttypes.h>
00055
00056
00057 #if !defined(CONFIG_LCD_SOFTINT_REFRESH) || (CONFIG_LCD_SOFTINT_REFRESH != 0 && CONFIG_LCD_SOFTINT_REFRESH != 1)
00058 #error CONFIG_LCD_SOFTINT_REFRESH must be defined to either 0 or 1
00059 #endif
00060 #if !defined(CONFIG_LCD_SOFTINT_REFRESH) || (CONFIG_LCD_SOFTINT_REFRESH != 0 && CONFIG_LCD_SOFTINT_REFRESH != 1)
00061 #error CONFIG_LCD_SOFTINT_REFRESH must be defined to either 0 or 1
00062 #endif
00063
00064
00065 #if CONFIG_LCD_SOFTINT_REFRESH
00066
00068 # define LCD_REFRESH_INTERVAL 20
00069
00070 #endif
00071
00073 #define LCD_PAGES 4
00074
00076 #define LCD_PAGESIZE (LCD_WIDTH / 2)
00077
00082 #define LCD_PF_DB0 PF4
00083 #define LCD_PF_DB1 PF5
00084 #define LCD_PF_DB2 PF6
00085 #define LCD_PF_DB3 PF7
00086 #define LCD_PD_DB4 PD4
00087 #define LCD_PD_DB5 PD5
00088 #define LCD_PD_DB6 PD6
00089 #define LCD_PD_DB7 PD7
00090 #define LCD_PB_A0 PB0
00091 #define LCD_PE_RW PE7
00092 #define LCD_PE_E1 PE2
00093 #define LCD_PE_E2 PE6
00094
00100 #define LCD_DATA_HI_PORT PORTD
00101 #define LCD_DATA_HI_PIN PIND
00102 #define LCD_DATA_HI_DDR DDRD
00103 #define LCD_DATA_HI_SHIFT 0
00104 #define LCD_DATA_HI_MASK 0xF0
00105
00111 #define LCD_DATA_LO_PORT PORTF
00112 #define LCD_DATA_LO_PIN PINF
00113 #define LCD_DATA_LO_DDR DDRF
00114 #define LCD_DATA_LO_SHIFT 4
00115 #define LCD_DATA_LO_MASK 0xF0
00116
00122 #define LCD_CLR_A0 (PORTB &= ~BV(LCD_PB_A0))
00123 #define LCD_SET_A0 (PORTB |= BV(LCD_PB_A0))
00124 #define LCD_CLR_RD (PORTE &= ~BV(LCD_PE_RW))
00125 #define LCD_SET_RD (PORTE |= BV(LCD_PE_RW))
00126 #define LCD_CLR_E1 (PORTE &= ~BV(LCD_PE_E1))
00127 #define LCD_SET_E1 (PORTE |= BV(LCD_PE_E1))
00128 #define LCD_CLR_E2 (PORTE &= ~BV(LCD_PE_E2))
00129 #define LCD_SET_E2 (PORTE |= BV(LCD_PE_E2))
00130 #define LCD_SET_E(x) (PORTE |= (x))
00131 #define LCD_CLR_E(x) (PORTE &= ~(x))
00132
00138 #define LCDF_E1 (BV(LCD_PE_E1))
00139 #define LCDF_E2 (BV(LCD_PE_E2))
00140
00143 #define LCD_READ ( \
00144 ((LCD_DATA_LO_PIN & LCD_DATA_LO_MASK) >> LCD_DATA_LO_SHIFT) | \
00145 ((LCD_DATA_HI_PIN & LCD_DATA_HI_MASK) >> LCD_DATA_HI_SHIFT) \
00146 )
00147
00149 #define LCD_WRITE(d) \
00150 do { \
00151 LCD_DATA_LO_PORT = (LCD_DATA_LO_PORT & ~LCD_DATA_LO_MASK) | (((d)<<LCD_DATA_LO_SHIFT) & LCD_DATA_LO_MASK); \
00152 LCD_DATA_HI_PORT = (LCD_DATA_HI_PORT & ~LCD_DATA_HI_MASK) | (((d)<<LCD_DATA_HI_SHIFT) & LCD_DATA_HI_MASK); \
00153 } while (0)
00154
00156 #define LCD_DB_OUT \
00157 do { \
00158 LCD_DATA_LO_DDR |= LCD_DATA_LO_MASK; \
00159 LCD_DATA_HI_DDR |= LCD_DATA_HI_MASK; \
00160 } while (0)
00161
00163 #define LCD_DB_IN \
00164 do { \
00165 LCD_DATA_LO_DDR &= ~LCD_DATA_LO_MASK; \
00166 LCD_DATA_HI_DDR &= ~LCD_DATA_HI_MASK; \
00167 } while (0)
00168
00170 #define LCD_DELAY_WRITE \
00171 do { \
00172 NOP; \
00173 NOP; \
00174 } while (0)
00175
00177 #define LCD_DELAY_READ \
00178 do { \
00179 NOP; \
00180 NOP; \
00181 NOP; \
00182 } while (0)
00183
00184
00189 #define LCD_CMD_DISPLAY_ON 0xAF
00190 #define LCD_CMD_DISPLAY_OFF 0xAE
00191 #define LCD_CMD_STARTLINE 0xC0
00192 #define LCD_CMD_PAGEADDR 0xB8
00193 #define LCD_CMD_COLADDR 0x00
00194 #define LCD_CMD_ADC_LEFT 0xA1
00195 #define LCD_CMD_ADC_RIGHT 0xA0
00196 #define LCD_CMD_STATIC_OFF 0xA4
00197 #define LCD_CMD_STATIC_ON 0xA5
00198 #define LCD_CMD_DUTY_32 0xA9
00199 #define LCD_CMD_DUTY_16 0xA8
00200 #define LCD_CMD_RMW_ON 0xE0
00201 #define LCD_CMD_RMW_OFF 0xEE
00202 #define LCD_CMD_RESET 0xE2
00203
00205 MOD_DEFINE(lcd)
00206
00207
00208
00209 #define LCDF_BUSY BV(7)
00210
00211 #if CONFIG_LCD_WAIT
00212
00225 #define WAIT_LCD \
00226 do { \
00227 uint8_t status; \
00228 LCD_DB_IN; \
00229 do { \
00230 LCD_SET_RD; \
00231 LCD_CLR_A0; \
00232 LCD_SET_E1; \
00233 LCD_DELAY_READ; \
00234 status = LCD_READ; \
00235 LCD_CLR_E1; \
00236 LCD_SET_A0; \
00237 LCD_CLR_RD; \
00238 } while (status & LCDF_BUSY); \
00239 LCD_DB_OUT; \
00240 } while (0)
00241
00242 #else
00243
00244 #define WAIT_LCD do {} while(0)
00245
00246 #endif
00247
00248
00255 DECLARE_WALL(wall_before_raster, WALL_SIZE)
00256 static uint8_t lcd_raster[RAST_SIZE(LCD_WIDTH, LCD_HEIGHT)];
00257 DECLARE_WALL(wall_after_raster, WALL_SIZE)
00258
00260 struct Bitmap lcd_bitmap;
00261
00262
00263 #if CONFIG_LCD_SOFTINT_REFRESH
00264
00266 static Timer *lcd_refresh_timer;
00267
00268 #endif
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294 static inline void lcd_cmd(uint8_t cmd, uint8_t chip)
00295 {
00296 WAIT_LCD;
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 LCD_WRITE(cmd);
00308
00309 LCD_CLR_A0;
00310 LCD_SET_E(chip);
00311 LCD_DELAY_WRITE;
00312 LCD_CLR_E(chip);
00313 LCD_SET_A0;
00314
00315 }
00316
00317
00318 static inline uint8_t lcd_read(uint8_t chip)
00319 {
00320 uint8_t data;
00321
00322 WAIT_LCD;
00323
00337 LCD_DB_IN;
00338
00339 LCD_SET_RD;
00340 LCD_SET_E(chip);
00341 LCD_DELAY_READ;
00342 data = LCD_READ;
00343 LCD_CLR_E(chip);
00344 LCD_CLR_RD;
00345
00346 LCD_DB_OUT;
00347
00348 return data;
00349 }
00350
00351
00352 static inline void lcd_write(uint8_t c, uint8_t chip)
00353 {
00354 WAIT_LCD;
00355
00369 LCD_WRITE(c);
00370
00371
00372 LCD_SET_E(chip);
00373 LCD_DELAY_WRITE;
00374 LCD_CLR_E(chip);
00375
00376
00377 }
00378
00379
00383 void lcd_setPwm(int duty)
00384 {
00385 ASSERT(duty >= LCD_MIN_PWM);
00386 ASSERT(duty <= LCD_MAX_PWM);
00387
00388 OCR3C = duty;
00389 }
00390
00391
00392 static void lcd_clear(void)
00393 {
00394 uint8_t page, j;
00395
00396 for (page = 0; page < LCD_PAGES; ++page)
00397 {
00398 lcd_cmd(LCD_CMD_COLADDR | 0, LCDF_E1 | LCDF_E2);
00399 lcd_cmd(LCD_CMD_PAGEADDR | page, LCDF_E1 | LCDF_E2);
00400 for (j = 0; j < LCD_PAGESIZE; j++)
00401 lcd_write(0, LCDF_E1 | LCDF_E2);
00402 }
00403 }
00404
00405
00406 static void lcd_writeRaster(const uint8_t *raster)
00407 {
00408 uint8_t page, rows;
00409 const uint8_t *right_raster;
00410
00411 CHECK_WALL(wall_before_raster);
00412 CHECK_WALL(wall_after_raster);
00413
00414 for (page = 0; page < LCD_PAGES; ++page)
00415 {
00416 lcd_cmd(LCD_CMD_PAGEADDR | page, LCDF_E1 | LCDF_E2);
00417 lcd_cmd(LCD_CMD_COLADDR | 0, LCDF_E1 | LCDF_E2);
00418
00419
00420 right_raster = raster + LCD_PAGESIZE;
00421 rows = LCD_PAGESIZE;
00422 do
00423 {
00424 lcd_write(*raster++, LCDF_E1);
00425 lcd_write(*right_raster++, LCDF_E2);
00426 }
00427 while (--rows);
00428 raster = right_raster;
00429 }
00430 }
00431
00435 void lcd_blitBitmap(Bitmap *bm)
00436 {
00437 MOD_CHECK(lcd);
00438 lcd_writeRaster(bm->raster);
00439 }
00440
00441
00442 #if CONFIG_LCD_SOFTINT_REFRESH
00443
00444 static void lcd_refreshSoftint(void)
00445 {
00446 lcd_blit_bitmap(&lcd_bitmap);
00447 timer_add(lcd_refresh_timer);
00448 }
00449
00450 #endif
00451
00452
00459 void lcd_init(void)
00460 {
00461 MOD_CHECK(timer);
00462
00463
00464 cpuflags_t flags;
00465 IRQ_SAVE_DISABLE(flags);
00466
00467 PORTB |= BV(LCD_PB_A0);
00468 DDRB |= BV(LCD_PB_A0);
00469
00470 PORTE &= ~(BV(LCD_PE_RW) | BV(LCD_PE_E1) | BV(LCD_PE_E2));
00471 DDRE |= BV(LCD_PE_RW) | BV(LCD_PE_E1) | BV(LCD_PE_E2);
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487 LCD_DB_OUT;
00488
00489
00490 IRQ_ENABLE;
00491 timer_delay(20);
00492 IRQ_SAVE_DISABLE(flags);
00493
00494 lcd_cmd(LCD_CMD_RESET, LCDF_E1 | LCDF_E2);
00495 lcd_cmd(LCD_CMD_DISPLAY_ON, LCDF_E1 | LCDF_E2);
00496 lcd_cmd(LCD_CMD_STARTLINE | 0, LCDF_E1 | LCDF_E2);
00497
00498
00499 INIT_WALL(wall_before_raster);
00500 INIT_WALL(wall_after_raster);
00501
00502 IRQ_RESTORE(flags);
00503
00504 lcd_clear();
00505 lcd_setpwm(LCD_DEF_PWM);
00506
00507 gfx_bitmapInit(&lcd_bitmap, lcd_raster, LCD_WIDTH, LCD_HEIGHT);
00508 gfx_bitmapClear(&lcd_bitmap);
00509
00510 #if CONFIG_LCD_SOFTINT_REFRESH
00511
00512
00513 lcd_refresh_timer = timer_new();
00514 ASSERT(lcd_refresh_timer != NULL);
00515 INITEVENT_INT(&lcd_refresh_timer->expire, (Hook)lcd_refresh_softint, 0);
00516 lcd_refresh_timer->delay = LCD_REFRESH_INTERVAL;
00517 timer_add(lcd_refresh_timer);
00518
00519 #endif
00520
00521 MOD_INIT(lcd);
00522 }