/*
 * OLED-Testprogramm für Display
 * WEH001602ALP von Winstar
 * http://www.eHaJo.de
 * (C) Hannes Jochriem, 2013
 * 
 * Pin-Belegung Display:
 * 1:	GND
 * 2:	VCC
 * 3:	N.C.
 * 4:	RS
 * 5:	R/W
 * 6:	ENABLE
 * 7:	Data0
 * 8:	Data1
 * 9:	Data2
 * 10:	Data3
 * 11:	Data4
 * 12:	Data5
 * 13:	Data6
 * 14:	Data7
 * 15:	N.C.
 * 16:	N.C.
 * 
 * µC-Belegung:
 * Data0:	PD0
 * Data1:	PD1
 * Data2:	PD2
 * Data3:	PD3
 * Data4:	PD4
 * Data5:	PD5
 * Data6:	PD6
 * Data7:	PD7
 * RS:		PD4		H: Daten, L: Befehl
 * R/W:		PD5		H: Lesen(MPU->Modul), L: Schreiben(MPU->Modul)
 * E:		PD6		Aktivieren H, H->L
 * 
 */
 
#define F_CPU 8000000UL     /* Interne 8MHz */
 
#include <avr/io.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <stdlib.h>
 
// Prototypen
void long_delay(uint16_t);
void sende_daten(uint8_t);
void sende_befehl(uint8_t);
void toggle_en(void);
void led_an(void);
void led_aus(void);
void schreibe_text(uint8_t, const char *);
 
// Globals
uint8_t _data_pins[4];
 
#define RS	(1<<PC3)
#define RW	(1<<PC4)
#define ENABLE	(1<<PC5)
#define LED	(1<<PC2)
#define DATA0	(1<<PD0)
#define DATA1	(1<<PD1)
#define DATA2	(1<<PD2)
#define DATA3	(1<<PD3)
#define DATA4	(1<<PD4)
#define DATA5	(1<<PD5)
#define DATA6	(1<<PD6)
#define DATA7	(1<<PD7)
 
int main(void)
{
	DDRD = 0xff;			// Datenport als Ausgang
	DDRC |= (LED|RS|RW|ENABLE);	// Steuerpins als Ausgang
	PORTD = 0;			// Datenport auf 0
	PORTC |= (RS|RS|ENABLE);	// Steuerpins auf 1
	led_an();			// "debug"-LED einschalten
	long_delay(500);		// Display benoetigt 500ms beim Power-up
	led_aus();			// "debug"-LED ausschalten
 
	sende_befehl(0x38);//function set
	_delay_us(5000);
	sende_befehl(0x38);//function set
	_delay_us(5000);
	sende_befehl(0x38);//function set
	_delay_us(5000);
	sende_befehl(0x38);//function set
	_delay_us(5000);
	sende_befehl(0x08);//display off
	_delay_us(5000);
	sende_befehl(0x06);//entry mode set//need to configure this cmd or char will move left not move right
	_delay_us(5000);
	sende_befehl(0x17);//Character mode and internel power on (have to turn on internel power to get the best brightness)
	_delay_us(5000);
	sende_befehl(0x01);//clear display
	_delay_us(5000);
	sende_befehl(0x02);//return home
	_delay_us(5000);
	sende_befehl(0x0c);//display on
 
	schreibe_text(0, "eHaJo.de");
	schreibe_text(1, "OLED-Display");
 
	while(1)
	{
		// Tue nix...
	}
	return 0;
}
 
void sende_daten(uint8_t zeichen)
{
	PORTC |= (RS);	// RS ist 1 bei Daten
	DDRD = 0xff;
	PORTD = zeichen;
	toggle_en();
}
 
void sende_befehl(uint8_t zeichen)
{
	PORTC &= ~(RS);	// RS ist 0 bei Befehlen
	DDRD = 0xff;
	PORTD = zeichen;
	toggle_en();
}
 
void toggle_en()
{	// ENABLE + RW werden getoggelt, es gibt keien Busy-Bit-Abfrage.
	PORTC &= ~(ENABLE | RW);
	_delay_us(500);
	PORTC |= (ENABLE | RW);
	_delay_us(500);
}
 
void schreibe_text(uint8_t zeile, const char *text)
{
	char zeichen;
 
	if(zeile == 0)
		sende_befehl((0x80)+0);	// Setze Adresse an die erste Position von Zeile 1
	else
		sende_befehl((0x80)+64);	// Setze Adresse an die erste Position von Zeile 2
	while ((zeichen = *text++)) 
	{	// Solange Zeichen vorhanden sind zum Display schicken
		sende_daten(zeichen);
	}
}
 
void led_an()
{
	PORTC |= LED;
}
 
void led_aus()
{	
	PORTC &= ~(LED);
}
 
void long_delay(uint16_t ms) 
{
        for(; ms>0; ms--) 
                _delay_ms(1);
}