Roteiro 10 EA870 2S2009

De DCA-Wiki

Contents

Roteiro 10 - Transmissão Serial Síncrona (QSPI) e o uso do display LCD

  • SPI - Transmissão Serial Síncrona / QSPI - Queued Serial Peripferal Interface
  • Uso do Liquid Cristal Display (LCD) - Veja Referência /6/, documento sobre SPECIFICATIONS FOR LCD MODULE -

Agradecimento

O desenvolvimento deste roteiro teve a grata contribuição de Guilherme A. Zalewski (buzzag@gmail.com) e Pedro Augusto (okaitt@gmail.com).

Introdução ao Experimento de Hoje

  • Neste experimento daremos início a transmissão serial síncrona (SPI) ou (QSPI onde Q significa: Enfileirar) do MCF para utilizarmos do display LCD presente na placa auxiliar. Mais uma vez teremos o código exemplo para o envio de bits para o LCD e a sua ativação. Este roteiro corresponde ao Cap 22 de http://www.freescale.com/files/32bit/doc/ref_manual/MCF52223RM.pdf

Roteiro de Estudos

  • 1. Explique e ilustre graficamente sucintamente a diferença entre uma transmissão utilizando-se do periférico QSPI (sícrono) e o UART (assíncrono).
  • 2. Na placa auxiliar, como é feita a seleção para a utilização do LCD?
  • 3. Como é possível distinguir dados e comandos no LCD?
  • 4. Qual o padrão utilizado para a inserção de caracteres no LCD?
  • 5. O que significa os comandos de configuração 0x38, 0x06, 0x0F e 0x01 enviadas ao LCD, visto no código exemplo "LCD/main.c"?
  • 6. Qual a função do periférico QSPI para o LCD?
  • 7. Qual a função do pino R/W do LCD? Por qual motivo ele está fixado a "0" na placa auxiliar?
  • 8. Como é dividida a QSPI RAM?
  • 9. Qual a função do registrador QMR?
  • 10. Para que servem os bits 13-10 do registrador QMR?
  • 11, Explique porque na UART deve-se configurar o clock, enqto no QSPI não é needs configurar, como exemplo use as ilustrações que V configurou os registradores nos roteiros (rot4 e outros).

Roteiro da Aula

O programa exemplo:

- Programa LCD/main.c

#include "support_common.h" /* include peripheral declarations and more */
#include "uart_support.h"
#include <stdio.h>

#define DDRAS	0x40100023
#define PORTAS	0x4010000B
#define PASPAR	0x4010006B
#define CLRAS	0x40100053
#define SETAS	0x4010003B


//Função que gera um delay suficiente para o LCD funcionar/processar
void delay(){
int i, j;
	for(i=0;i<40;i++)
	{
		for(j=0;j<1000;j++)
		{
		}
	}
}
	
//FUNÇÃO DE TRANSMISSÃO QSPI
void envia_spi(uint8 sinal)
{
MCF_QSPI_QAR = 0x0000;		//Registrador de endereço aponta para área de transmissão
MCF_QSPI_QDR = sinal;		//É armazenado o dado a ser transmitido
MCF_QSPI_QDLYR |= 0x8000;	//Dá início à transmissão
}


//CONFIGURAÇÃO DO PERIFERICO QSPI
void configura_spi()
{
MCF_GPIO_PQSPAR |= 0x1555;	//A porta porta QS exerce função QSPI (Configura PQSPAR)

//Configuração do registrador "Mode"
MCF_QSPI_QMR &= ~(MCF_QSPI_QMR_CPHA);	//Dados mudam na borda de subida do clk
MCF_QSPI_QMR |= MCF_QSPI_QMR_MSTR;		//Modo MASTER (Obrigatorio)
MCF_QSPI_QMR |= MCF_QSPI_QMR_BITS(0x8);	//8bits por transmissão
MCF_QSPI_QMR |= MCF_QSPI_QMR_BAUD(0x2);	//Baud Rate 10Mhz

MCF_QSPI_QDLYR = 0x0000;	//Delay register = 0 Delays são todos zero
MCF_QSPI_QWR = 0x1000;		//Abaixa nível de CS0 e informa transmisão única
							//Lembrando-se que o HLT pára transmissão
MCF_QSPI_QIR |= MCF_QSPI_QIR_SPIF;	//Garante que o "finish flag" é alto nível

//Programa a transmissão
MCF_QSPI_QAR = 0x0020;	//Registrador de endereço aponta para área de comandos 
MCF_QSPI_QDR = 0x7E00;	//Programa a transmissão (nº de bits...)
}

///////////////////////////////////////////////////////////////////////////////////////////


//Função Principal
int main(void)
{
unsigned char m_swa[12] = {"SwA - GRAVAR"};
unsigned char m_swb[9] = {"SwB - LER"};
unsigned char m_123[13] = {"Escolha 1 2 3"};
unsigned char m_ra[10] = {"Entre RA: "};
unsigned char m_nome[11] = {"Entre Nome:"};
unsigned char m_msg[15] = {"Entre Mensagem:"};
unsigned char m_exibir_ra[10] = {"Meu RA eh:"};
unsigned char m_exibir_nome[12] = {"Meu nome eh:"};
unsigned char m_exibir_msg[9] = {"Mensagem:"};

uint8 configuracao[5] = {0x38, 0x38, 0x06, 0x0F, 0x01};	//Configuracao do LCD

int i;

uint8 *ddras = (uint8 *)DDRAS;
uint8 *portas = (uint8 *)PORTAS;
uint8 *paspar = (uint8 *)PASPAR;
uint8 *clras = (uint8 *)CLRAS;

configura_spi();	//Configura o SPI (Configuração fixa)

*paspar = 0x00;		//Define a porta AS como IO comum
*ddras = 0x03;		//Define a porta AS como saída
*clras = 0x00;		//Zera a porta AS

//Lembrando que a porta AS1 escolhe para onde os dados do SPI vão:
//DAC (0) ou LCD (1)

//No caso do LCD, quando desejamos mandar um COMANDO, AS0 = 0
//Para enviarmos um caracter, AS0 = 1

delay();			//Espera um tempo para o LCD inicializar

//Seleciona LCD com escrita de COMANDO
*portas = 0x02;		// AS1 = 1  e AS0 = 0

//Envia os comandos de configuração do LCD
for (i=0; i<5; i++)
        {
	envia_spi(configuracao[i]);	//Envia o comando
	delay();
        }

*portas = 0x03;		//Seleciona o LCD com escrita de CARACTER		

//Envia os caracteres para o LCD
for (i=0; i<10; i++)
	{
	envia_spi(mensagem[i]);	//Envia o caracter
	delay();
	}

}
  • Crie um novo projeto no CodeWarrior e utilize o código acima como código principal (main).
  • Procure entender exatamente o que o código faz.

Agora, para a confecção do relatório, é preciso a função varre_teclado() utilizada no Roteiro 7. Basta incluir os "DEFINES" no programa LCD/main.c e incluir a função no seu código. Lembrando que é necessário um vetor de tamanho 12 de entrada para a função, que retorna os botões pressionados. Abaixo a função:

Função varre_teclado()

#define PORTTC  0x4010000F
#define DDRTC   0x40100027
#define PORTUBP 0x40100042
#define DDRUB   0x4010002A
#define PUBPAR  0x40100072

void varre_teclado(int situacao[])
{
	int i,j, mask;
	int aterra[4] = {0x0E000000,0x0D000000,0x0B000000,0x07000000}; /*Sequencia de saidas para as portas*/
	int io[4] = {0x01000000,0x02000000,0x04000000,0x08000000}; /*Sequencia de configuracao de porta*/
	int *end_aterra = (int *)aterra;  /*Recebe o endereco do vetor de dados*/ 
	int *end_io  = (int *)io; /*Recebe o endereco do vetor de dados*/ 
	int *end_key = (int *)situacao; /*Recebe o endereco do vetor de status do teclado*/ 
	int *porttc  = (int *)PORTTC;
	int *ddrtc   = (int *)DDRTC;
	int *portubp = (int *)PORTUBP;
	int *ddrub   = (int *)DDRUB;
	int *pubpar  = (int *)PUBPAR;

	*pubpar = 0xFF; /*Configura porta UB para trabalhar como porta comum*/
	*ddrub = 0xFF;	/*Configura UB como ENTRADA*/

	/*Rotina para varrer teclado. Previne contra curto quando mais teclas estao apertadas ao mesmo tempo*/
	for (i=0; i<4; i++){  

	/*Faz a leitura da linha i*/
	*ddrtc = *end_io; /*Configura TCi como saida e o restante como entrada*/
	*porttc = *end_aterra; /*Seta ZERO no bit TCi*/

	end_aterra++;  /*Pega o dado seguinte, aterra ou nao*/
	end_io++; /*Pega a configuracao seguinte, Entrada ou Saida*/
	mask = 0x01000000; /*Configura mascara para detectar botao apertado ou nao*/

		for (j=0;j<3;j++){
		
		/*Caso o botao esteja apertado, o bit i do registrador PORTUBP estara em ZERO*/
		if(!(mask & *portubp)) *end_key = 1;
		else *end_key = 0;
        
        mask = mask <<1; /*Verifica bit seguido (colula j)*/
    	end_key++; /*Passa para proximo digito no vetor TECLADO*/
		}
	}
}

Agora, para a confecção do relatório, é necessário as funções de envio e recebimento da UART0 em C visto no relatório de PWM e Hexadecimal. Abaixo estão as funções:

#include "uart_support.h"  //Nao se esqueça de colocar este include
...
int main(){
...
uart_init(0,80000,9600);  //Apenas inicialize uma vez o periférico
...
uart_putchar(0,'A');  //Envia um char
...
algum_char = uart_getchar(0);  //Pega um char digitado
...
}

Relatório

QUESTÕES:- (Veja na página da disciplina, na opção calendário a data referente à entrega de cada relatório).

  • Nas questões a seguir ilustre graficamente ou justifique com configurações que V fez
  • a. Explique e ilustre graficamente a diferença entre uma transmissão utilizando-se o periférico QSPI (sícrono) e o UART (assíncrono).
  • b. Na placa auxiliar, como é feita a seleção para a utilização do LCD?
  • c. Como é possível distinguir dados e comandos no LCD?
  • d. Qual o padrão utilizado para a inserção de caracteres no LCD?
  • e. O que significa os comandos de configuração 0x38, 0x06, 0x0F e 0x01 enviadas ao LCD, visto no código exemplo "LCD/main.c"?
  • f. Qual a função do periférico QSPI para o LCD?
  • g. Qual a função do pino R/W do LCD? Por qual motivo ele está fixado a "0" na placa auxiliar?
  • h. Como é dividida a QSPI RAM?
  • i. Qual a função do registrador QMR?
  • j. Para que servem os bits 13-10 do registrador QMR?
  • k. Explique porque na UART deve-se configurar o clock no início da Tr/R, enqto no QSPI não é needs configurar, como exemplo use as ilustrações que V configurou os registradores nos roteiros (rot4 e outros).


PROGRAMA:-

  • 1. Faça o fluxograma para o programa exemplo.
  • 2. Utilizando como base o exemplo, construa um programa que:
    • Inicie com a frase "SwA - GRAVAR" na primeira linha do LCD e a frase "SwB - LER" na segunda linha do LCD.
    • Ao pressionar o push button "SWA" entre na opção de gravar frases, que deverá:
      • - Ter a mensagem "Escolha 1 2 3" na primeira linha e NADA na segunda.
      • - Detectar pelo teclado da placa auxiliar as opções 1, 2 ou 3 (uma por vez).
        • Caso seja pressionado o push button 1 , mostrar a frase "Entre Nome:" na primeira linha e pular o cursor para o primeiro caracter da segunda linha. Esperar a entrada da frase (com no máximo 16 caracteres) pela serial (utilizando o HT, lembrando de prevenir contra a entrada de mais de 16 caracteres). Cada caracter digitado no HT, e portanto recebido, deverá ser guardado e também mostrado no LCD (ao digitar "A" no HT, por exemplo, deve ser mostrado no LCD o caracter "A" e consequentemente gravado). Detecte o "ENTER" para terminar com a tranmissão e gravar a frase desejada. Após o fim da gravação da frase, volte ao menu INICIAL.
        • Caso seja pressionado o push button 2 , mostrar a frase "Entre RA: " na primeira linha e pular o cursor para o primeiro caracter da segunda linha. Esperar a entrada da frase (com no máximo 16 caracteres) pela serial (utilizando o HT, lembrando de prevenir contra a entrada de mais de 16 caracteres). Cada caracter digitado no HT, e portanto recebido, deverá ser guardado e também mostrado no LCD (ao digitar "9" no HT, por exemplo, deve ser mostrado no LCD o caracter "9" e consequentemente gravado). Detecte o "ENTER" para terminar com a tranmissão e gravar a frase desejada. Após o fim da gravação da frase, volte ao menu INICIAL.
        • Caso seja pressionado o push button 3 , mostrar a frase "Entre Mensagem:" na primeira linha e pular o cursor para o primeiro caracter da segunda linha. Esperar a entrada da frase (com no máximo 16 caracteres) pela serial (utilizando o HT, lembrando de prevenir contra a entrada de mais de 16 caracteres). Cada caracter digitado no HT, e portanto recebido, deverá ser guardado e também mostrado no LCD (ao digitar "M" no HT, por exemplo, deve ser mostrado no LCD o caracter "M" e consequentemente gravado). Detecte o "ENTER" para terminar com a tranmissão e gravar a frase desejada. Após o fim da gravação da frase, volte ao menu INICIAL.
    • Ao pressionar o push button "SWB" entre na opção de ler as frases, que deverá:
      • - Ter a mensagem "Escolha 1 2 3" na primeira linha e NADA na segunda.
      • - Detectar pelo teclado da placa auxiliar as opções 1, 2 ou 3 (uma por vez).
        • Caso seja pressionado o push button 1 , mostrar a frase "Meu nome eh:" na primeira linha e mostrar a mensagem gravada anteriormente na segunda linha do display. Faça um delay para que a mensagem seja mostrada por um tempo e depois volte ao menu INICIAL.
        • Caso seja pressionado o push button 2 , mostrar a frase "Meu RA eh:" na primeira linha e mostrar a mensagem gravada anteriormente na segunda linha do display. Faça um delay para que a mensagem seja mostrada por um tempo e depois volte ao menu INICIAL.
        • Caso seja pressionado o push button 3 , mostrar a frase "Mensagem:" na primeira linha e mostrar a mensagem gravada anteriormente na segunda linha do display. Faça um delay para que a mensagem seja mostrada por um tempo e depois volte ao menu INICIAL.

DICAS: - Utilize de BRANCHs incondicionais para pular de uma parte a outra do código, voltar no código ou qualquer outra finalidade utilizando o assembly.

'''Exemplo:'''
int main(){
...
asm{ INICIO: nop  ; nop = nenhuma operação
}
...
...
if (i == 0){
...
asm{ BRA INICIO  ; pula para label INICIO
}
...
...
}

- Para um bom tempo de delay para mostrar as frases gravadas, utilize este código:

for (i=0; i<2000; i++)
{
  delay();  //Ele gerará um tempo suficiente para lermos a mensagem.
}
  • 3. Faça um fluxograma do seu programa, feito no item 2.

Referências

Ferramentas pessoais