/************************************************
Escreve no LCD usando fila circular com interrupcao tipo IRQ
Sistemas Embarcados
Marcos Augusto Stemmer
*************************************************/
#include <arch/nxp/lpc24xx.h>
#define PCLK 12000000
/* Macros para habilitar/desabilitar IRQ no CPSR */
#define habilitaIRQ() asm volatile(\
	"mrs r3, cpsr\n" \
	"bic r3, r3, # 0x80\n" \
	"msr cpsr, r3\n")

#define desabilitaIRQ() asm volatile(\
	"mrs r3, cpsr\n" \
	"orr r3, r3, # 0x80\n" \
	"msr cpsr, r3\n")
/*Mascaras no FIO4PIN3 */
#define LCD_E 0x80
#define LCD_RS 0x40
#define LCD_RW (1<<23)

#define TAMFILA 0x100
volatile int inicio, fim;
short fila[TAMFILA];

void FIQ_Routine(void) __attribute__ ((interrupt("FIQ")));
void FIQ_Routine(void){} // Agora a FIQ nao faz nada

void T0_irq(void) __attribute__ ((interrupt("IRQ")));

void T0_irq(void)
{
int k;
k=T0IR;		/* T0IR identifica quem causou a int	*/
if(fim != inicio){
	if(fila[inicio] & 0x100)
		FIO1CLR3 = LCD_RS;	// RS=0 Comando
	else	FIO1SET3 = LCD_RS;	// RS=1 Caractere
	FIO2PIN0 = fila[inicio++];	// Pega caractere do inicio e cloca no LCD
	if(inicio == TAMFILA) inicio=0;
	FIO1SET3 = LCD_E;	// Liga E
	FIO1CLR3 = LCD_E;	// Desliga E
	}
T0IR = k;	/* Deve limpar a INT no T0IR */
VICVectAddr = 0;
}

#define LCDcomando(c) LCDputchar(c+0x100);
// Rotina LCDputchar coloca o caractere no fim da fila
void LCDputchar(int c)
{
while((fim - inicio)%TAMFILA > TAMFILA-2);
fila[fim++] = c;
if(fim == TAMFILA) fim=0;
}

void LCDputs(char *s)
{
while(*s) LCDputchar(*s++);
}

int main (void)
{
MEMMAP = 2;	/* 2 Mapeia para RAM */
//MEMMAP = 1;	/* 1 Mapeia vetores para a FLASH */

T0TCR = 2; T0TCR=0;	/* Limpa e habilita T0 */
/* Preescalonador do T0 para incrementar 1000 vezes por segundo */
T0PR = (PCLK / 50) - 1;
T0TCR=1;
desabilitaIRQ();
T0IR = 1;	// Limpa indicador de interrupcao do T0MR0
T0MCR = 1+2;	// Interrompe e inicializa em T0MR0
T0MR0 = 1;	// Intervalo de 2 ms
/* Seleciona e habilita no VIC */
VICIntSelect &= ~0x10;	/* Timer0=bit 4 como IRQ	*/
VICIntEnable = 0x10;	/* Habilita int do Timer0	*/
VICVectAddr4 = (unsigned long)T0_irq;	// Nome da rotina de atendimento
//VICVectPriority4 = 8;	// Prioridade da IRQ do timer T0
inicio=fim=0;
habilitaIRQ();	// Habilita no reg CPSR do ARM
FIO2DIR |= 0xff;	/* P0.0 a P0.7 como saidas (dados do LCD) */
FIO1DIR |= (LCD_E | LCD_RS) << 24;
FIO4DIR |= LCD_RW;
FIO4CLR = LCD_RW;
FIO1CLR3=LCD_E;
LCDcomando(0x38);
LCDcomando(0x38);
LCDcomando(1);
LCDcomando(0xf);
LCDputs("Teste do LCD");
LCDcomando(0xc0);
LCDputs("com IRQ do T0");
do	{

	} while(1);
return 0;
}

/* Estas rotinas sao chamados pelo crt.S. 
Devem existir, mas ainda nao estao sendo usadas */
void UNDEF_Routine(){}
void SWI_Routine(){}
