lcd_32122a_avr.c

Go to the documentation of this file.
00001 
00045 #include "lcd_32122a_avr.h"
00046 
00047 #include "cfg/cfg_lcd.h"
00048 
00049 #include <cfg/macros.h> /* BV() */
00050 #include <cfg/debug.h>
00051 #include <cfg/module.h>
00052 
00053 #include <gfx/gfx.h>
00054 #include <drv/timer.h>
00055 
00056 #include <cpu/irq.h>
00057 #include <cpu/types.h>
00058 
00059 #include <avr/io.h>
00060 
00061 #include <stdbool.h>
00062 #include <inttypes.h>
00063 
00064 #warning TODO:Refactor this module. Split code to hw file.
00065 
00066 /* Configuration sanity checks */
00067 #if !defined(CONFIG_LCD_SOFTINT_REFRESH) || (CONFIG_LCD_SOFTINT_REFRESH != 0 && CONFIG_LCD_SOFTINT_REFRESH != 1)
00068     #error CONFIG_LCD_SOFTINT_REFRESH must be defined to either 0 or 1
00069 #endif
00070 #if !defined(CONFIG_LCD_SOFTINT_REFRESH) || (CONFIG_LCD_SOFTINT_REFRESH != 0 && CONFIG_LCD_SOFTINT_REFRESH != 1)
00071     #error CONFIG_LCD_SOFTINT_REFRESH must be defined to either 0 or 1
00072 #endif
00073 
00074 
00075 #if CONFIG_LCD_SOFTINT_REFRESH
00076 
00078 #   define LCD_REFRESH_INTERVAL 20  /* 20ms -> 50fps */
00079 
00080 #endif /* CONFIG_LCD_SOFTINT_REFRESH */
00081 
00083 #define LCD_PAGES 4
00084 
00086 #define LCD_PAGESIZE (LCD_WIDTH / 2)
00087 
00092 #define LCD_PF_DB0   PF4
00093 #define LCD_PF_DB1   PF5
00094 #define LCD_PF_DB2   PF6
00095 #define LCD_PF_DB3   PF7
00096 #define LCD_PD_DB4   PD4
00097 #define LCD_PD_DB5   PD5
00098 #define LCD_PD_DB6   PD6
00099 #define LCD_PD_DB7   PD7
00100 #define LCD_PB_A0    PB0
00101 #define LCD_PE_RW    PE7
00102 #define LCD_PE_E1    PE2
00103 #define LCD_PE_E2    PE6
00104 
00110 #define LCD_DATA_HI_PORT    PORTD
00111 #define LCD_DATA_HI_PIN     PIND
00112 #define LCD_DATA_HI_DDR     DDRD
00113 #define LCD_DATA_HI_SHIFT   0
00114 #define LCD_DATA_HI_MASK    0xF0
00115 
00121 #define LCD_DATA_LO_PORT    PORTF
00122 #define LCD_DATA_LO_PIN     PINF
00123 #define LCD_DATA_LO_DDR     DDRF
00124 #define LCD_DATA_LO_SHIFT   4
00125 #define LCD_DATA_LO_MASK    0xF0
00126 
00132 #define LCD_CLR_A0   (PORTB &= ~BV(LCD_PB_A0))
00133 #define LCD_SET_A0   (PORTB |=  BV(LCD_PB_A0))
00134 #define LCD_CLR_RD   (PORTE &= ~BV(LCD_PE_RW))
00135 #define LCD_SET_RD   (PORTE |=  BV(LCD_PE_RW))
00136 #define LCD_CLR_E1   (PORTE &= ~BV(LCD_PE_E1))
00137 #define LCD_SET_E1   (PORTE |=  BV(LCD_PE_E1))
00138 #define LCD_CLR_E2   (PORTE &= ~BV(LCD_PE_E2))
00139 #define LCD_SET_E2   (PORTE |=  BV(LCD_PE_E2))
00140 #define LCD_SET_E(x) (PORTE |= (x))
00141 #define LCD_CLR_E(x) (PORTE &= ~(x))
00142 
00148 #define LCDF_E1 (BV(LCD_PE_E1))
00149 #define LCDF_E2 (BV(LCD_PE_E2))
00150 
00153 #define LCD_READ ( \
00154         ((LCD_DATA_LO_PIN & LCD_DATA_LO_MASK) >> LCD_DATA_LO_SHIFT) | \
00155         ((LCD_DATA_HI_PIN & LCD_DATA_HI_MASK) >> LCD_DATA_HI_SHIFT) \
00156     )
00157 
00159 #define LCD_WRITE(d) \
00160     do { \
00161         LCD_DATA_LO_PORT = (LCD_DATA_LO_PORT & ~LCD_DATA_LO_MASK) | (((d)<<LCD_DATA_LO_SHIFT) & LCD_DATA_LO_MASK); \
00162         LCD_DATA_HI_PORT = (LCD_DATA_HI_PORT & ~LCD_DATA_HI_MASK) | (((d)<<LCD_DATA_HI_SHIFT) & LCD_DATA_HI_MASK); \
00163     } while (0)
00164 
00166 #define LCD_DB_OUT \
00167     do { \
00168         LCD_DATA_LO_DDR |= LCD_DATA_LO_MASK; \
00169         LCD_DATA_HI_DDR |= LCD_DATA_HI_MASK; \
00170     } while (0)
00171 
00173 #define LCD_DB_IN \
00174     do { \
00175         LCD_DATA_LO_DDR &= ~LCD_DATA_LO_MASK; \
00176         LCD_DATA_HI_DDR &= ~LCD_DATA_HI_MASK; \
00177     } while (0)
00178 
00180 #define LCD_DELAY_WRITE \
00181     do { \
00182         NOP; \
00183         NOP; \
00184     } while (0)
00185 
00187 #define LCD_DELAY_READ \
00188     do { \
00189         NOP; \
00190         NOP; \
00191         NOP; \
00192     } while (0)
00193 
00194 
00199 #define LCD_CMD_DISPLAY_ON  0xAF
00200 #define LCD_CMD_DISPLAY_OFF 0xAE
00201 #define LCD_CMD_STARTLINE   0xC0
00202 #define LCD_CMD_PAGEADDR    0xB8
00203 #define LCD_CMD_COLADDR     0x00
00204 #define LCD_CMD_ADC_LEFT    0xA1
00205 #define LCD_CMD_ADC_RIGHT   0xA0
00206 #define LCD_CMD_STATIC_OFF  0xA4
00207 #define LCD_CMD_STATIC_ON   0xA5
00208 #define LCD_CMD_DUTY_32     0xA9
00209 #define LCD_CMD_DUTY_16     0xA8
00210 #define LCD_CMD_RMW_ON      0xE0
00211 #define LCD_CMD_RMW_OFF     0xEE
00212 #define LCD_CMD_RESET       0xE2
00213 
00215 MOD_DEFINE(lcd)
00216 
00217 
00218 /* Status flags */
00219 #define LCDF_BUSY BV(7)
00220 
00221 #if CONFIG_LCD_WAIT
00222 
00235 #define WAIT_LCD \
00236     do { \
00237         uint8_t status; \
00238         LCD_DB_IN; \
00239         do { \
00240             LCD_SET_RD; \
00241             LCD_CLR_A0; \
00242             LCD_SET_E1; \
00243             LCD_DELAY_READ; \
00244             status = LCD_READ; \
00245             LCD_CLR_E1; \
00246             LCD_SET_A0; \
00247             LCD_CLR_RD; \
00248         } while (status & LCDF_BUSY); \
00249         LCD_DB_OUT; \
00250     } while (0)
00251 
00252 #else /* CONFIG_LCD_WAIT */
00253 
00254 #define WAIT_LCD do {} while(0)
00255 
00256 #endif /* CONFIG_LCD_WAIT */
00257 
00258 
00265 DECLARE_WALL(wall_before_raster, WALL_SIZE)
00266 static uint8_t lcd_raster[RAST_SIZE(LCD_WIDTH, LCD_HEIGHT)];
00267 DECLARE_WALL(wall_after_raster, WALL_SIZE)
00268 
00270 struct Bitmap lcd_bitmap;
00271 
00272 
00273 #if CONFIG_LCD_SOFTINT_REFRESH
00274 
00276 static Timer *lcd_refresh_timer;
00277 
00278 #endif /* CONFIG_LCD_SOFTINT_REFRESH */
00279 
00280 
00281 /*
00282 static bool lcd_check(void)
00283 {
00284     uint8_t status;
00285     uint16_t retries = 32768;
00286     PORTA = 0xFF;
00287     DDRA = 0x00;
00288     do {
00289         cbi(PORTC, PCB_LCD_RS);
00290         sbi(PORTC, PCB_LCD_RW);
00291         sbi(PORTC, PCB_LCD_E);
00292         --retries;
00293         NOP;
00294         status = PINA;
00295         cbi(PORTC, PCB_LCD_E);
00296         cbi(PORTC, PCB_LCD_RW);
00297     } while ((status & LCDF_BUSY) && retries);
00298 
00299     return (retries != 0);
00300 }
00301 */
00302 
00303 
00304 static inline void lcd_32122_cmd(uint8_t cmd, uint8_t chip)
00305 {
00306     WAIT_LCD;
00307 
00308     /*      __              __
00309      * A0   __\____________/__
00310      *
00311      * R/W  __________________
00312      *            ______
00313      * E1   _____/      \_____
00314      *
00315      * DATA --<============>--
00316      */
00317     LCD_WRITE(cmd);
00318     //LCD_DB_OUT;
00319     LCD_CLR_A0;
00320     LCD_SET_E(chip);
00321     LCD_DELAY_WRITE;
00322     LCD_CLR_E(chip);
00323     LCD_SET_A0;
00324     //LCD_DB_IN;
00325 }
00326 
00327 
00328 static inline uint8_t lcd_32122_read(uint8_t chip)
00329 {
00330     uint8_t data;
00331 
00332     WAIT_LCD;
00333 
00347     LCD_DB_IN;
00348     //LCD_SET_A0;
00349     LCD_SET_RD;
00350     LCD_SET_E(chip);
00351     LCD_DELAY_READ;
00352     data = LCD_READ;
00353     LCD_CLR_E(chip);
00354     LCD_CLR_RD;
00355     //LCD_CLR_A0;
00356     LCD_DB_OUT;
00357 
00358     return data;
00359 }
00360 
00361 static inline void lcd_32122_write(uint8_t c, uint8_t chip)
00362 {
00363     WAIT_LCD;
00364 
00378     LCD_WRITE(c);
00379     //LCD_DB_OUT;
00380     //LCD_SET_A0;
00381     LCD_SET_E(chip);
00382     LCD_DELAY_WRITE;
00383     LCD_CLR_E(chip);
00384     //LCD_CLR_A0;
00385     //LCD_DB_IN;
00386 }
00387 
00388 static void lcd_32122_clear(void)
00389 {
00390     uint8_t page, j;
00391 
00392     for (page = 0; page < LCD_PAGES; ++page)
00393     {
00394         lcd_32122_cmd(LCD_CMD_COLADDR | 0, LCDF_E1 | LCDF_E2);
00395         lcd_32122_cmd(LCD_CMD_PAGEADDR | page, LCDF_E1 | LCDF_E2);
00396         for (j = 0; j < LCD_PAGESIZE; j++)
00397             lcd_32122_write(0, LCDF_E1 | LCDF_E2);
00398     }
00399 }
00400 
00401 
00402 static void lcd_32122_writeRaster(const uint8_t *raster)
00403 {
00404     uint8_t page, rows;
00405     const uint8_t *right_raster;
00406 
00407     CHECK_WALL(wall_before_raster);
00408     CHECK_WALL(wall_after_raster);
00409 
00410     for (page = 0; page < LCD_PAGES; ++page)
00411     {
00412         lcd_32122_cmd(LCD_CMD_PAGEADDR | page, LCDF_E1 | LCDF_E2);
00413         lcd_32122_cmd(LCD_CMD_COLADDR | 0, LCDF_E1 | LCDF_E2);
00414 
00415         /* Super optimized lamer loop */
00416         right_raster = raster + LCD_PAGESIZE;
00417         rows = LCD_PAGESIZE;
00418         do
00419         {
00420             lcd_32122_write(*raster++, LCDF_E1);
00421             lcd_32122_write(*right_raster++, LCDF_E2);
00422         }
00423         while (--rows);
00424         raster = right_raster;
00425     }
00426 }
00427 
00428 #if CONFIG_LCD_SOFTINT_REFRESH
00429 
00430 static void lcd_32122_refreshSoftint(void)
00431 {
00432     lcd_blit_bitmap(&lcd_bitmap);
00433     timer_add(lcd_refresh_timer);
00434 }
00435 
00436 #endif /* CONFIG_LCD_SOFTINT_REFRESH */
00437 
00441 void lcd_32122_setPwm(int duty)
00442 {
00443     ASSERT(duty >= LCD_MIN_PWM);
00444     ASSERT(duty <= LCD_MAX_PWM);
00445 
00446     OCR3C = duty;
00447 }
00448 
00452 void lcd_32122_blitBitmap(Bitmap *bm)
00453 {
00454     MOD_CHECK(lcd);
00455     lcd_32122_writeRaster(bm->raster);
00456 }
00457 
00458 
00465 void lcd_32122_init(void)
00466 {
00467     MOD_CHECK(timer);
00468 
00469     // FIXME: interrupts are already disabled when we get here?!?
00470     cpu_flags_t flags;
00471     IRQ_SAVE_DISABLE(flags);
00472 
00473     PORTB |= BV(LCD_PB_A0);
00474     DDRB |= BV(LCD_PB_A0);
00475 
00476     PORTE &= ~(BV(LCD_PE_RW) | BV(LCD_PE_E1) | BV(LCD_PE_E2));
00477     DDRE |= BV(LCD_PE_RW) | BV(LCD_PE_E1) | BV(LCD_PE_E2);
00478 
00479 /* LCD hw reset
00480     LCD_RESET_PORT |= BV(LCD_RESET_BIT);
00481     LCD_RESET_DDR |= BV(LCD_RESET_BIT);
00482     LCD_DELAY_WRITE;
00483     LCD_DELAY_WRITE;
00484     LCD_RESET_PORT &= ~BV(LCD_RESET_BIT);
00485     LCD_DELAY_WRITE;
00486     LCD_DELAY_WRITE;
00487     LCD_RESET_PORT |= BV(LCD_RESET_BIT);
00488 */
00489     /*
00490      * Data bus is in output state most of the time:
00491      * LCD r/w functions assume it is left in output state
00492      */
00493     LCD_DB_OUT;
00494 
00495     // Wait for RST line to stabilize at Vcc.
00496     IRQ_ENABLE;
00497     timer_delay(20);
00498     IRQ_SAVE_DISABLE(flags);
00499 
00500     lcd_32122_cmd(LCD_CMD_RESET, LCDF_E1 | LCDF_E2);
00501     lcd_32122_cmd(LCD_CMD_DISPLAY_ON, LCDF_E1 | LCDF_E2);
00502     lcd_32122_cmd(LCD_CMD_STARTLINE | 0, LCDF_E1 | LCDF_E2);
00503 
00504     /* Initialize anti-corruption walls for raster */
00505     INIT_WALL(wall_before_raster);
00506     INIT_WALL(wall_after_raster);
00507 
00508     IRQ_RESTORE(flags);
00509 
00510     lcd_32122_clear();
00511     lcd_32122_setPwm(LCD_DEF_PWM);
00512 
00513     gfx_bitmapInit(&lcd_bitmap, lcd_raster, LCD_WIDTH, LCD_HEIGHT);
00514     gfx_bitmapClear(&lcd_bitmap);
00515 
00516 #if CONFIG_LCD_SOFTINT_REFRESH
00517 
00518     /* Init IRQ driven LCD refresh */
00519     lcd_refresh_timer = timer_new();
00520     ASSERT(lcd_refresh_timer != NULL);
00521     INITEVENT_INT(&lcd_refresh_timer->expire, (Hook)lcd_refresh_softint, 0);
00522     lcd_refresh_timer->delay = LCD_REFRESH_INTERVAL;
00523     timer_add(lcd_refresh_timer);
00524 
00525 #endif /* CONFIG_LCD_SOFTINT_REFRESH */
00526 
00527     MOD_INIT(lcd);
00528 }
00529