/*
    Programme de démonstration de pilotage d'un afficheur LCD I2C avec un
    PIC 18F2455. Pour le schéma et les explications, voir :

 	<http://www.jacquet80.eu/pic/>

	L'afficheur LCD I2C utilisé était le BTHQ 21605AV-YETF-LED04-I2C-5V de
	Batron. Le programme et/ou le schéma sera à adapter pour un autre modèle
	d'afficheur (brochage différent, timing différent, etc.)

    Copyright (C) 2009 Christophe Jacquet <http://www.jacquet80.eu/>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


#include <p18f4550.h>
#include <i2c.h>

#pragma config FOSC = HSPLL_HS // mode oscillateur extérieur HS, PLL activée, HS utilisé pour l'USB ;
#pragma config PLLDIV = 5 // division par 5 de la fréquence avant la PLL (prescaler) car il FAUT TOUJOURS du 4 MHz. Quartz à 20 MHz => PLLDIV = 5
#pragma config CPUDIV = OSC4_PLL6 // division par 4 de la fréquence en sortie de la PLL (postscaler).

#pragma config MCLRE = OFF
#pragma config WDT = OFF
#pragma config LVP = OFF


// Adresse I2C standard des afficheurs LCD
#define LCDADDR 0x76

// Redéfinition des trois fonctions write(), stop() et start()
// pour qu'elles fassent d'abord un idle()
void iic_write(unsigned char c) {
	IdleI2C();
	WriteI2C(c);
}

void iic_stop(void) {
	IdleI2C();
	StopI2C();
}

void iic_start(void) {
	IdleI2C();
	StartI2C();
}

void Display_init(void);
void Write_text(void);


// Initialise le LCD
void Display_init(void) {
	iic_start();
	iic_write(LCDADDR);  // LCD's I2C slave address
	iic_write(0x00);	 // Control byte for instruction
	iic_write(0x34);	 // DL: 8 bits, M:  16 by two line  display, SL: 1:18, H: normal instruction set
	iic_write(0x0C);     // D: Display on, C: curser off, B: blink off
	iic_write(0x06);	 // I/D: increment, S: no shift

	iic_write(0x35);     // DL: 8 bits, M: 16 by two line, SL: 1:18, H: extended instruction set
	iic_write(0x04);     // P: left to right, Q: top to bottom
	iic_write(0x10);     // TC1: 0, TC2: 0
	iic_write(0x42);     // HV Stages 3
	iic_write(0x9f);     // set Vlcd, store to VA
	iic_write(0x34);     // DL: 8 bits, M:  two line, SL: 1:18, H: normal instruction set

	iic_write(0x80);     // DDRAM Address set to 00hex
	iic_write(0x02);     // return home
	iic_stop();
}  


// Affiche des caractères
void Write_text(void) {
	int i;
	iic_start();
	iic_write(LCDADDR);  // I2C slave Address
	iic_write(0x00);     // Control byte for Instruction
	iic_write(0x80);     // DDRAM Address set to 00hex
	iic_stop();

	iic_start();
	iic_write(LCDADDR);  // I2C slave Adress
	iic_write(0x40);     // Control byte for Data
	for (i=1;i<=16;i++) {
		iic_write(0xC0+i);      // Write ABCDE....
	}
	iic_stop();

	iic_start();
	iic_write(LCDADDR);  // I2C slave Adress
	iic_write(0x00);     // Control byte for Instruction
	iic_write(0xc0);     // DDRAM Address set to 10hex
	iic_stop();

	iic_start();
	iic_write(LCDADDR);  // I2C slave Address
	iic_write(0x40);     // Control byte for Data
	for (i=1;i<=16;i++) {
		iic_write(0xe0+i);      // Write abcde....
	}
	iic_stop();
}


// Affiche deux lignes de texte
void Write_2lines(const rom char* t, const rom char*b) {
	int i;
	iic_start();
	iic_write(LCDADDR);  // LCD's I2C slave Address
	iic_write(0x00);     // Control byte for Instruction
	iic_write(0x80);     // DDRAM Address set to 00hex
	iic_stop();

	iic_start();
	iic_write(LCDADDR);  // I2C slave Adress
	iic_write(0x40);     // Control byte for Data
	for (i=0;i<16 && t[i] !=0;i++) {
		iic_write(0x80+t[i]);      // Write ABCDE....
	}
	iic_stop();

	iic_start();
	iic_write(LCDADDR);  // I2C slave Adress
	iic_write(0x00);     // Control byte for Instruction
	iic_write(0xc0);     // DDRAM Address set to 10hex
	iic_stop();

	iic_start();
	iic_write(LCDADDR);  // I2C slave Address
	iic_write(0x40);     // Control byte for Data
	for (i=0;i<16 && b[i] != 0;i++) {
		iic_write(0x80+b[i]);      // Write abcde....
	}
	iic_stop();
}


void main(void)
{
	// PORTB en entrée numérique
	TRISB = 0xFF;
	ADCON1 = 0xE;

	// En mode I2C Master, SSPADD contient la valeur de configuration
	// du générateur de débit binaire (baud rate generator). La valeur
	// suivante donne de bons résultats
	SSPADD = 0x27;

	OpenI2C(MASTER, SLEW_OFF);

	Display_init();
	//Write_text();
	Write_2lines("I2C LCD Display ", "www.jacquet80.eu");

	for(;;) {}
}
