JuiceBox Code Lcd Main

From eLinux.org
Revision as of 02:00, 14 July 2007 by Chris (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

(file: lcd_1.c)

#include "stdint.h"
#include "s3c44b0x.h"

const uint8_t lookup[]=
{  0xff,          /* white */
   0xe0,          /* red */
   0x1c,          /* green */
   0x03,          /* blue */
   0xe0 | 0x1c,   /* red + green */
   0x1c | 0x03,   /* green + blue */
   0xe0 | 0x03,   /* red + blue */
   0,             /* black */
};

void delay_ms(uint32_t delay)
{
   /* Delay hand tuned for use with 66.428MHz clock
      (PLLCON = 0x55051, PLL reference of 10MHz).
      Assumes code is running from cached memory.
      fixme: use a hardware timer instead.
   */      

   uint32_t ms;
   uint32_t i;
   for (ms=0; ms<delay; ms++)
      for (i=0; i<13288; i++);  
}

void tune_delay()
{
   /* Swap TXD0 line to I/O and toggle it to tune delay_ms() */
   *pcone&=~0x0c;
   *pcone|=0x04;

   /* Expect 50 Hz, or 10ms from edge to edge */
   for (;;)
   {
      *pdate|=0x02;
      delay_ms(10);
      *pdate&=(~0x02);
      delay_ms(10);
   }
}

void uart_init()
{
   /* Assign TX and RX pins to the UART */
   *pcone&=~0x0c;
   *pcone|=0x08;

   /* 8 bits, 2 stop bits, no parity, non-IrDA mode */
   *ulcon0=0x03;

   /* Polled RX, polled TX, no break, no loopback, no error interrupts, 
      no RX fifo timeouts, TX level interrupts
   */
   *ucon0=0x205;

   /* Clear and enable FIFOs */
   *ufcon0=7;

   /* Disable automatic flow control on handshake lines */
   *umcon0=0;

   /* Set baud rate divisor
      0x23 = 115.2k baud with 66.428MHz clock
      (OK, it's really 115.327kbaud, or 0.11% fast).
   */
   *ubrdiv0=0x23;

}

void cpu_init()
{
   /* Set clock rate to 66.428MHz, just in case the JB has
      it set wrong
   */
   *pllcon=0x55051;
   
   /* Be sure we're in cacheable memory
      Can the framebuffer be in cache too?
   */
   *ncachbe0=0x80002000;
   *ncachbe1=0x0;
}

void uart_tx_string(const uint8_t* s)
{
   while (*s)
   {
      /* Spin until fifo isn't full */
      while ((*ufstat0 & 0x0200)) {};
      *utxh0=*s;
      s++;
   }
}

void set_lcd_brightness(uint32_t brightness)
{
   /* Set LCD backlight brightness
      0 is dark, 0xa00 is full bright
   */   
   *tcmpb1=brightness;
}

uint32_t *framebuffer_start()
{
   /* Return with starting address of LCD framebuffer */
   return (uint32_t*)(((*lcdsaddr1) & 0x07ffffff) << 1);
}

void clear_lcd()
{
   uint32_t i;
   uint32_t *addr=framebuffer_start();
   
   /* fill entire framebuffer, 32 bits at a whack */
   for (i=0; i<240*160; i+=4)
   {
      *addr=0;
      ++addr;
   }
}

void h_line(uint32_t y, uint8_t color)
{
   uint32_t x;
   uint32_t c=(color << 24) | (color << 16) | (color << 8) | color;
   uint32_t *addr=framebuffer_start();
   addr+=(240*y)/4;

   /* Draw horizontal line, 4 bytes at a time */
   for (x=0; x<240; x+=4)
   {
      *addr++=c;
   }
}

void v_line(uint32_t x, uint8_t color)
{
   uint32_t y;
   uint8_t *addr=(uint8_t*)framebuffer_start();
   addr+=x;

   /* Assumes 240 pixels/line */
   for (y=0; y<160; y++)
   {
      *addr=color;
      addr+=240;
   }
}

void h_loop()
{
   /* Bounce a horizontal line up and down the screen. */
   uint32_t i, color;

   clear_lcd();
   for (color=0; color<7; color++)
   {
      for (i=0; i<159; i++)
      {
         h_line(i+1, lookup[color]);
         h_line(i, 0);
         delay_ms(6);
      }
      for (i=160; i>0; i--)
      {
         h_line(i-1, lookup[color]);
         h_line(i, 0);
         delay_ms(6);
      }
   }
}

void v_loop()
{
   /* Bounce a vertical line back and forth */
   uint32_t x, color;

   clear_lcd();
   for (color=0; color<7; color++)
   {
      for (x=0; x<240; x++)
      {
         v_line(x+1, lookup[color]);
         v_line(x, 0);
         delay_ms(6);
      }
      for (x=240; x>0; x--)
      {
         v_line(x-1, lookup[color]);
         v_line(x, 0);
         delay_ms(6);
      }
   }
}

void v_fill_loop()
{
   /* Vertical screen fill demo */

   uint32_t x, color;

   for (color=0; color<7;)
   {
      for (x=0; x<240; x++)
      {
         v_line(x+1, lookup[color]);
         delay_ms(6);
      }
      color++;   

      for (x=240; x>0; x--)
      {
         v_line(x-1, lookup[color]);
         delay_ms(6);
      }
      color++;   
   }
}

void h_fill_loop()
{
   /* Horizontal screen fill demo */

   uint32_t i, color;

   for (color=0; color<7;)
   {
      for (i=0; i<160; i++)
      {
         h_line(i, lookup[color]);
         delay_ms(6);
      }
      color++;

      for (i=160; i>0; i--)
      {
         h_line(i-1, lookup[color]);
         delay_ms(6);
      }
      color++;
   }
}

void lcd_init()
{
   /* Set ENVID (bit 0 of lcdcon1) to 0 to disable panel */
   *lcdcon1=0x10C0DF40;    /* LCDCON1  (LCD Control 1) */

   /* Configure the LCD panel, using settings borrowed from
      the built in self test code.
      Looks like it's one byte/pixel, using the palette LUT registers.
   */
   *lcdcon2=0x0141649F;    /* LCDCON2  (LCD Control 2) */
   *lcdcon3=0x00000000;    /* LCDCON3  (LCD Control 3) */
   *lcdsaddr1=0x1E0F288A;  /* LCDSADDR1  (Frame Upper Buffer Start Address 1) */
   *lcdsaddr2=0x21AF738A;  /* LCDSADDR2  (Frame Lower Buffer Start Address 2) */
   *lcdsaddr3=0x00000078;  /* LCDSADDR3  (Virtual Screen Address) */
   *redlut=0xFDB96420;     /* REDLUT  (RED Lookup Table) */
   *greenlut=0xFDB96420;   /* GREENLUT  (GREEN Lookup Table) */
   *bluelut=0x0000FB40;    /* BLUELUT  (BLUE Lookup Table) */
   *dp1_2=0x0000A5A5;      /* DP1_2  (Dithering Pattern duty 1/2) */
   *dp4_7=0x0BA5DA65;      /* DP4_7  (Dithering Pattern duty 4/7) */
   *dp3_5=0x000A5A5F;      /* DP3_5  (Dithering Pattern duty 3/5) */
   *dp2_3=0x00000D6B;      /* DP2_3  (Dithering Pattern duty 2/3) */
   *dp5_7=0x0EB7B5ED;      /* DP5_7  (Dithering Pattern duty 5/7) */
   *dp3_4=0x00007DBE;      /* DP3_4  (Dithering Pattern duty 3/4) */
   *dp4_5=0x0007EBDF;      /* DP4_5  (Dithering Pattern duty 4/5) */
   *dp6_7=0x07FDFBFE;      /* DP6_7  (Dithering Pattern duty 6/7) */
   *dithmode=0x00000000;   /* DITHMODE  (Dithering Mode) */
   
   /* Enable the panel now that the settings are in place */
   *lcdcon1=0x10C0DF41;    /* LCDCON1  (LCD Control 1) */
}

void solid_fill(uint8_t color)
{
   /* Fill the entire framebuffer with a solid color */
   uint32_t i, c;
   uint32_t *addr=framebuffer_start();

   c=(color << 24) | (color << 16) | (color << 8) | color;

   for (i=0; i<240*160; i+=4)
   {
      *addr++=c;
   }
}

void color_test()
{
   /* Try to display all 256 potential color
      I'm not at all sure this works, but I left it in.
   */
   uint32_t x, y, c;
   uint8_t *addr=(uint8_t*)framebuffer_start();

   for (y=0; y<160; y++)
   {
      for (x=0; x<240; x++)
      {
         c=((x /15) << 4) + (y/10);
         *addr++=c;
      }
   }
}

int main(void)
{
   uint32_t i;

   /* Init */
   cpu_init();
   uart_init();
   lcd_init();

   /* Hi */
   uart_tx_string("\r\n\r\nJuicebox: Hello, world! (" 
      __FILE__ ", " __DATE__ ", " __TIME__ ")");
   delay_ms(100);

   /* Demo loop */
   for (;;)
   {
      uart_tx_string("\r\n   Vertical fill demo...");
      v_fill_loop();

      uart_tx_string("\r\n   Horizontal fill demo...");
      h_fill_loop();

      uart_tx_string("\r\n   Vertical line demo...");
      v_loop();

      uart_tx_string("\r\n   Horizontal line demo...");
      h_loop();

      uart_tx_string("\r\n   Color swatch demo...");
      color_test();
      delay_ms(2000);

      uart_tx_string("\r\n   Color flood demo...");
      for (i=0; i<255; i++)
      {
         solid_fill(i);
         delay_ms(50);
      }
   }

   return 0;
}