/******************************************************************************/
/*  OLED example.   8 bit mode                                           */
/*      Spark Fun Electronics   5/3/06   OSO                                 */
/******************************************************************************/
/*                                                                            */
/*                                                                            */
/******************************************************************************/

#include "LPC21xx.h"   // device spefific microcontroller file  (we used LPC2138 ARM)


// data bus for LCD, pins on port 0
#define D0 16
#define D1 17
#define D2 18
#define D3 19
#define D4 20
#define D5 21
#define D6 22
#define D7 23

// OLED data port
#define LCD_DATA 0x00FF0000

// other OLED pins
#define LCD_RW    0x00000080
#define LCD_RS    0x04000000
#define LCD_RD    0x00008000
#define LCD_RSTB  0x80000000
#define LCD_CS    0x02000000


// inialize OLED
void OLED_init(void);

// reset Controller
void Reset_SSD1339(void);

// write command or data
void write_c(unsigned char out_command);
void write_d(unsigned char out_data);

// these write data to the OLED on 8 bit data bus,  depends on MCU
void LCD_out(unsigned char cmd);
unsigned int get_LCD_port(unsigned char data);

// these functions set / clear pins for OLED control lines.  they accecpt a 0 or 1 
void RD(char stat);
void RW(char stat);
void DC(char stat);
void RES(char stat);
void CS(char stat);

// a stupid delay
void delay_ms(int count);

// LPC 2138 MCU initialization
void Initialize(void);
void feed(void);


int main (void) {
  int   i = 0;

  // Initialize
  Initialize();
  OLED_init();

  delay_ms(120);


  write_c(0x8e);    // clear window command
  write_d(0);
  write_d(0);
  write_d(130);
  write_d(130);

  delay_ms(100);
  
  write_c(0x92);    // fill enable command
  write_d(0x01); 
  
  delay_ms(10);

  // draw 100 random circles
  for(i = 0;i < 100;i++){
      write_c(0x86);    // draw circle command
      write_d(rand() % 130);
      write_d(rand() % 130);
      write_d(rand() % 64);
      write_d(rand());
      write_d(rand());
      write_d(rand());
      write_d(rand());

      delay_ms(10);
  }

  // write directly to ram,  this fills up bottom 1/3 of display with color pattern
  write_c(0x5c);
  for (i = 0; i < 2000; i++){
  write_c(0x5c);  
   write_d(i);
   write_d(i);
   write_d(i);
  }


  for(;;);
} // main()

// a stupid delay
void delay_ms(int count){
  int i;
  count *= 2600;
  for (i = 0; i < count; i++){
  asm volatile ("nop");
  }
}



/**********************************************************
                      Initialize
**********************************************************/

#define PLOCK 0x400

void Initialize(void)  {
   
	// Setting Multiplier and Divider values
  	PLLCFG=0x23;
  	feed();
  
	// Enabling the PLL */	
	PLLCON=0x1;
	feed();
  
	// Wait for the PLL to lock to set frequency
	while(!(PLLSTAT & PLOCK)) ;
  
	// Connect the PLL as the clock source
	PLLCON=0x3;
	feed();
  
	// Enabling MAM and setting number of clocks used for Flash memory fetch (4 cclks in this case)
	MAMCR=0x2;
	MAMTIM=0x4;
  
	// Setting peripheral Clock (pclk) to System Clock (cclk)
	VPBDIV=0x1;

}


void feed(void)
{
  PLLFEED=0xAA;
  PLLFEED=0x55;
}


void OLED_init(void)
{
  LCD_out(0);
  RD(1);
  DC(0);
  RW(0);
  CS(0);
  Reset_SSD1339();
  write_c(0xa0); // Set Re-map / Color Depth
  write_d(0x34);//0xb4); // 262K 8bit R->G->B
  write_c(0xa1); // Set display start line
  write_d(0x00); // 00h start
  //write_c(0xa2); // Set display offset
  //write_d(0x80); // 80h start
  write_c(0xA6); // Normal display
  write_c(0xad); // Set Master Configuration
  write_d(0x8e); // DC-DC off & external VcomH voltage & external pre-charge voltage
  write_c(0xb0); // Power saving mode
  write_d(0x05);
  write_c(0xb1); // Set pre & dis_charge
  write_d(0x11); // pre=1h dis=1h
  write_c(0xb3); // clock & frequency
  write_d(0xf0); // clock=Divser+1 frequency=fh
  write_c(0xbb); // Set pre-charge voltage of color A B C
  write_d(0x1c); // color A
  write_d(0x1c); // color B
  write_d(0x1c); // color C
  write_c(0xbe); // Set VcomH
  write_d(0x1f); //
  write_c(0xc1); // Set contrast current for A B C
  write_d(0xaa); // Color A
  write_d(0xb4); // Color B
  write_d(0xc8); // Color C
  write_c(0xc7); // Set master contrast
  write_d(0x0f); // no change
  write_c(0xca); // Duty
  write_d(0x7f); // 127+1
  write_c(0xaf); // Display on
}
void Reset_SSD1339(void)
{
  RES(0);
  delay_ms(100);
  RES(1);
}
void write_c(unsigned char out_command)
{
  DC(0);CS(0);RW(0);
  //delay_ms(1);
  LCD_out(out_command);
 // delay_ms(1);
  RW(1);
  CS(1);
  DC(1);
}

void write_d(unsigned char out_data)
{
  DC(1);CS(0);RW(0);
 // delay_ms(1);
  LCD_out(out_data);
 // delay_ms(1);
  RW(1);
  CS(1);
  DC(1);
}

// these functions set / clear pins for LCD control lines.  they accecpt a 0 or 1 
void RD(char stat)
{
	IODIR0 |= LCD_RD;				// RD is P0.18, set to output
	if (stat)	
		IOSET0 |= LCD_RD;
	else
		IOCLR0 |= LCD_RD;
}

void RW(char stat)
{
	IODIR0 |= LCD_RW;				// RW is P0.17, set to output
	if (stat)	
		IOSET0 |= LCD_RW;
	else
		IOCLR0 |= LCD_RW;
}

void DC(char stat)
{
	IODIR0 |= LCD_RS;				// RS is P0.30, set to output
	if (stat)	
		IOSET0 |= LCD_RS;
	else
		IOCLR0 |= LCD_RS;
}

void RES(char stat)
{
	IODIR0 |= LCD_RSTB;				// RSTB is P0.7, set to output
	if (stat)	
		IOSET0 |= LCD_RSTB;
	else
		IOCLR0 |= LCD_RSTB;
}

void CS(char stat)
{
	IODIR0 |= LCD_CS;				// RSTB is P0.7, set to output
	if (stat)	
		IOSET0 |= LCD_CS;
	else
		IOCLR0 |= LCD_CS;
}




// send to the LCD
void LCD_out(unsigned char cmd)
{
  IODIR0 |= LCD_DATA;           	// set lcd data pins to output					
  IOCLR0 |= LCD_DATA;				// clear all pins
  IOSET0 |= get_LCD_port(cmd);	  	// set port
}


unsigned int get_LCD_port(unsigned char data)
{
	return ((data & 0x01) << D0) | (((data >> 1) & 0x01) << D1) | (((data >> 2) & 0x01) << D2) | 
		(((data >> 3) & 0x01) << D3) | (((data >> 4) & 0x01) << D4) | 
		(((data >> 5) & 0x01) << D5) | (((data >> 6) & 0x01) << D6) | (((data >> 7) & 0x01) << D7);
}







