/*
 * 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:	N.C.
 * 5:	N.C.
 * 6:	N.C.
 * 7:	N.C.
 * 8:	N.C.
 * 9:	N.C.
 * 10:	N.C.
 * 11:	N.C.
 * 12:	SCL
 * 13:	SDO
 * 14:	SDI
 * 15:	N.C.
 * 16:	CS
 * 
 * µC-Belegung:
 * SCL: PD2
 * SDO: PD1
 * SDI: PD0
 * 
 */
 
#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_clk(void);
void led_an(void);
void led_aus(void);
void schreibe_text(uint8_t, const char *);
 
#define CS  (1<<PD3)
#define SCL (1<<PD2)
#define SDI (1<<PD1)
#define SDO (1<<PD0)
#define LED (1<<PC2)
 
 
int main(void)
{
	DDRD |= (SCL | SDO | CS);	// Ausgang
	DDRC |= LED;
	DDRD &= ~(SDI);			// Eingang
	PORTD |= (SCL | CS);		// SCL auf High
	led_an();			// "debug"-LED einschalten
	long_delay(500);		// Display benoetigt 500ms beim Power-up
	led_aus();			// "debug"-LED ausschalten
 
	sende_befehl(0b00111001);	// Function set: 8bit, 2 Zeilen, 5x8 Punkte, Westeurop. Charset
	_delay_us(500);
	sende_befehl(0b00001100);	// Display on. Display an, Cursor aus, Blinken aus.
	_delay_us(500);
	sende_befehl(0b00000001);	// Display clear
	_delay_us(500);
	sende_befehl(0b00000010);	// Display home
	_delay_us(500);
	sende_befehl(0b00000110);	// Entry mode: Dekrement, no shift.
	_delay_us(500);
 
	schreibe_text(0, "eHaJo.de");
	schreibe_text(1, "OLED-Display");
 
	while(1)
	{
		// Tue nix...
	}
	return 0;
}
 
void sende_daten(uint8_t zeichen)
{
	uint8_t i;
	// Ersten zwei Bit sind RS und RW:
	PORTD &= ~CS;		// CS auf 0
	PORTD |= (SDO);		// RS = 1
	toggle_clk();
	PORTD &= ~(SDO);	// RW = 0
	toggle_clk();
 
	for(i=0;i<8;i++)
	{	// Zeichen abarbeiten
		if(zeichen & 0x80)
			PORTD |= (SDO);
		else
			PORTD &= ~(SDO);
		toggle_clk();
		zeichen=zeichen<<1;
	}	
	PORTD |= CS;	// CS auf 1
}
 
void sende_befehl(uint8_t zeichen)
{
	uint8_t i;
	// Ersten zwei Bit sind RS und RW:
	PORTD &= ~CS;		// CS auf 0
	PORTD &= ~(SDO);	// RS = 0
	toggle_clk();
	PORTD &= ~(SDO);	// RW = 0
	toggle_clk();
 
	for(i=0;i<8;i++)
	{	// Zeichen abarbeiten
		if(zeichen & 0x80)
			PORTD |= (SDO);
		else
			PORTD &= ~(SDO);
		toggle_clk();
		zeichen=zeichen<<1;
	}	
	PORTD |= CS;	// CS auf 1
}
 
void toggle_clk()
{
	PORTD &= ~(SCL);
	_delay_us(1);
	PORTD |= (SCL);
	_delay_us(1);
}
 
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);
}