Relatório 5

073588 PEDRO AUGUSTO MARQUES DE CARVALHO

Relatório Referente as semanas 9 e 10

Parte 1: Placa funcionando com Programas de Piscar LED

Parte referente à aula 9.

Laço simples utilizando o cristal externo

O programa que faz piscar o LED utilizando-se um laço simples com um contador para fazer passar o tempo de CPU foi descrito pelo outro membro do grupo (Renan Fioritti). No caso aqui descrito, utlizando-se do cristal externo, o programa que faz piscar o LED é semelhante, entretando, inicialmente se configura o microcontrolador para utilização do relógio externo, o cristal montado na placa. Para tanto, foi inicializado um projeto novo através do processor expert. Nele foi escolhida uma fonte de relógio externa e selecionada a opção "Cristal Oscillator" como mostra a Figura 1. Foi ainda setado o valor de clock, que é o mesmo do interno e clock interno desabilitado.

/media/Attachments/courseEA079_1S2010/Mped_5/cristal.bmp

Figura 1: Processor Expert para a configuração do Cristal Oscilador externo

O código gerado consiste basicamente na configuração do oscilador externo. Ele pode ser visto no arquivo "Cpu.c" que é chamado pela função PE_low_level_init que pode ser vista abaixo:

/* SCGC1: MTIM1=1,TPM2=1,TPM1=1,ADC=1,IIC2=1,IIC1=1,SCI2=1,SCI1=1 */
setReg8(SCGC1, 0xFF);
/* SCGC2: SCI3=1,FTSR=1,IRQ=1,KBI2=1,KBI1=1,RTC=1,SPI2=1,SPI1=1 */
setReg8(SCGC2, 0xFF);
/* SCGC3: PTH=0,PTG=1,PTF=1,PTE=1,PTD=1,PTC=1,PTB=1,PTA=1 */
setReg8(SCGC3, 0x7F);
/* SCGC4: ??=1,??=1,??=1,MTIM2=1,MC=1,MB=0,FEC=1,PTJ=1 */
setReg8(SCGC4, 0xFB);
/* Common initialization of the CPU registers */
/* PTASE: PTASE7=0,PTASE6=0,PTASE5=0,PTASE4=0,PTASE3=0,PTASE2=0,PTASE1=0,PTASE0=0 */
setReg8(PTASE, 0x00);
/* PTBSE: PTBSE7=0,PTBSE6=0,PTBSE5=0,PTBSE4=0,PTBSE3=0,PTBSE2=0,PTBSE1=0,PTBSE0=0 */
setReg8(PTBSE, 0x00);
/* PTCSE: PTCSE7=0,PTCSE6=0,PTCSE5=0,PTCSE4=0,PTCSE3=0,PTCSE2=0,PTCSE1=0,PTCSE0=0 */
setReg8(PTCSE, 0x00);
/* PTDSE: PTDSE7=0,PTDSE6=0,PTDSE5=0,PTDSE4=0,PTDSE3=0,PTDSE2=0,PTDSE1=0,PTDSE0=0 */
setReg8(PTDSE, 0x00);
/* PTESE: PTESE7=0,PTESE6=0,PTESE5=0,PTESE4=0,PTESE3=0,PTESE2=0,PTESE1=0,PTESE0=0 */
setReg8(PTESE, 0x00);
/* PTFSE: PTFSE7=0,PTFSE6=0,PTFSE5=0,PTFSE4=0,PTFSE3=0,PTFSE2=0,PTFSE1=0,PTFSE0=0 */
setReg8(PTFSE, 0x00);
/* PTGSE: PTGSE3=0,PTGSE2=0,PTGSE1=0,PTGSE0=0 */
clrReg8Bits(PTGSE, 0x0F);
/* PTJSE: PTJSE1=0,PTJSE0=0 */
clrReg8Bits(PTJSE, 0x03);
/* PTADS: PTADS7=1,PTADS6=1,PTADS5=1,PTADS4=1,PTADS3=1,PTADS2=1,PTADS1=1,PTADS0=1 */
setReg8(PTADS, 0xFF);
/* PTBDS: PTBDS7=1,PTBDS6=1,PTBDS5=1,PTBDS4=1,PTBDS3=1,PTBDS2=1,PTBDS1=1,PTBDS0=1 */
setReg8(PTBDS, 0xFF);
/* PTCDS: PTCDS7=1,PTCDS6=1,PTCDS5=1,PTCDS4=1,PTCDS3=1,PTCDS2=1,PTCDS1=1,PTCDS0=1 */
setReg8(PTCDS, 0xFF);
/* PTDDS: PTDDS7=1,PTDDS6=1,PTDDS5=1,PTDDS4=1,PTDDS3=1,PTDDS2=1,PTDDS1=1,PTDDS0=1 */
setReg8(PTDDS, 0xFF);
/* PTEDS: PTEDS7=1,PTEDS6=1,PTEDS5=1,PTEDS4=1,PTEDS3=1,PTEDS2=1,PTEDS1=1,PTEDS0=1 */
setReg8(PTEDS, 0xFF);
/* PTFDS: PTFDS7=1,PTFDS6=1,PTFDS5=1,PTFDS4=1,PTFDS3=1,PTFDS2=1,PTFDS1=1,PTFDS0=1 */
setReg8(PTFDS, 0xFF);
/* PTGDS: PTGDS7=0,PTGDS6=0,PTGDS5=0,PTGDS4=0,PTGDS3=1,PTGDS2=1,PTGDS1=1,PTGDS0=1 */
setReg8(PTGDS, 0x0F);
/* PTJDS: ??=0,??=0,PTJDS5=0,PTJDS4=0,PTJDS3=0,PTJDS2=0,PTJDS1=1,PTJDS0=1 */
setReg8(PTJDS, 0x03);
/* PTAIFE: PTAIFE7=0,PTAIFE6=0,PTAIFE5=0,PTAIFE4=0,PTAIFE3=0,PTAIFE2=0,PTAIFE1=0,PTAIFE0=0 */
setReg8(PTAIFE, 0x00);
/* PTBIFE: PTBIFE7=0,PTBIFE6=0,PTBIFE5=0,PTBIFE4=0,PTBIFE3=0,PTBIFE2=0,PTBIFE1=0,PTBIFE0=0 */
setReg8(PTBIFE, 0x00);
/* PTCIFE: PTCIFE7=0,PTCIFE6=0,PTCIFE5=0,PTCIFE4=0,PTCIFE3=0,PTCIFE2=0,PTCIFE1=0,PTCIFE0=0 */
setReg8(PTCIFE, 0x00);
/* PTDIFE: PTDIFE7=0,PTDIFE6=0,PTDIFE5=0,PTDIFE4=0,PTDIFE3=0,PTDIFE2=0,PTDIFE1=0,PTDIFE0=0 */
setReg8(PTDIFE, 0x00);
/* PTEIFE: PTEIFE7=0,PTEIFE6=0,PTEIFE5=0,PTEIFE4=0,PTEIFE3=0,PTEIFE2=0,PTEIFE1=0,PTEIFE0=0 */
setReg8(PTEIFE, 0x00);
/* PTFIFE: PTFIFE7=0,PTFIFE6=0,PTFIFE5=0,PTFIFE4=0,PTFIFE3=0,PTFIFE2=0,PTFIFE1=0,PTFIFE0=0 */
setReg8(PTFIFE, 0x00);
/* PTGIFE: PTGIFE3=0,PTGIFE2=0,PTGIFE1=0,PTGIFE0=0 */
clrReg8Bits(PTGIFE, 0x0F);
/* PTJIFE: PTJIFE1=0,PTJIFE0=0 */
clrReg8Bits(PTJIFE, 0x03);
/* PTDPF1: D6=0,D5=3,D4=3 */
clrSetReg8Bits(PTDPF1, 0x30, 0x0F);
/* PTCPF2: C3=0 */
clrReg8Bits(PTCPF2, 0xC0);
/* SOPT3: CS=0,PCS=0 */
clrReg8Bits(SOPT3, 0x1F);
/* ### Shared modules init code ... */
/* INTC_WCR: ENB=1,??=0,??=0,??=0,??=0,MASK=0 */
setReg8(INTC_WCR, 0x80);
/* Set initial interrupt priority 0 */
asm {
  move.w SR,D0;
  andi.l #0xF8FF,D0;
  move.w D0,SR;
}

Ela basicamente configura o microcontrolador para receber o clock externo do oscilador e desabilita a referência interna de clock, como foi visto no relatório 3, onde as modificações nos registradores SOPT1, SPMSC1, SPMSC2, SPMSC3, MCGC1, MCGC2, MCGC3 e MCGC4 foram analisadas mais profundamente.

Por fim, a função main é mostrada abaixo:

void main(void)
{
    int i;
    PE_low_level_init();

    PTFDD = 0x80; // inicializa PTF7 como saída
    PTFD = 0;  // inicializa PTF com o valor 0

    for(;;){
      for(i=0; i<1000000; i++){
      // Contador para gastar tempo de processamento
      }
      PTFD_PTFD7 = ~PTFD_PTFD7;  // inverte a saída PTF7
    }
 }

Nela, inicialmente é declarada a variável inteira i que terá utilidade no contador. Após ser feita a definição de clock externa através da função PE_low_level_init() são feitas as definições da porta F que acessa o LED. Ela é configurada como saída e o pino 7 é inicialmente definido com o valor lógico zero. O "for" indefinido é utilizado para deixar o programa em um LOOP infinito (como as interrupções não foram habilitadas, não se faz necessário se preocupar o Watchdog Timer). Dentro desse LOOP, o contador criado com outro "FOR" e com o auxílio da variável i gasta tempo de cpu. Depois deste tempo gasto, o valor do pino 7 é invertido, fazendo com que o LED se apague e acenda em intervalos de tempo iguais. Esse tempo pode ser razoavelmente controlado incrementando ou decrementando o valor limite da variável i. Contudo, se for desejado um tempo específico, esse não é o método mais indicado.

Cristal externo, temporizador e interrupção

Neste segundo programa utilizando da placa já montada, foi utilizado um módulo timer (MTIM1) com sua interrupção mantendo a fonte de relógio como o cristal externo. Como foi feito no programa anterior, inicialmente foi configurado o cristal externo como fonte de clock e desabilitada a referência interna. Isso pode ser novamente visualizado na função PE_low_level_init() e na Figura 1. Em seguida, foi inicializado o módulo timer. Para tanto, novamente foi utilizado o Processor Expert como base. Foi adicionado o módulo timer na opção dos Periféricos que se encontram no chip do MCF51CN128 ("On-chip peripheral") como pode ser visto na Figura 2. Nesse periférico selecionado, as opções escolhidas são:

-MTIM1 (Módulo Timer 1)

-Fonte de Clock Fixa (é a frequência usada pelo microcontrolador)

-Prescaler de 64

-O registrador de módulo de 255

A combinação do prescaler com o registrador de módulo gera uma contagem de período de 1s. Essas opções podem ser visualizadas na Figura 3.

/media/Attachments/courseEA079_1S2010/Mped_5/timerum.bmp

Figura 2: Obtenção do módulo Timer no Processor Expert

É na Figura 3 também que são exibidas as configurações para utilizar a interrupção do timer. Primeiramente é ativada a interrupção com a opção "Overflow Interrupt" e em seguida definindo-se interrupção de prioridade nível 1 (que é a definição padrão). O campo "ISR name" é de extrema importância. Nele se define o nome da função que tratará a interrupção. Por fim, pede-se ao Processor Expert para ser chamada a inicialização do timer selecionando a opção "Call init method".

/media/Attachments/courseEA079_1S2010/Mped_5/timerdois.bmp

Figura 3: Configuração do módulo timer no Processor Expert

O código de inicialização do módulo timer resultante é mostrado abaixo:

void MTIM3_Init(void)
{
  /* MTIM1MOD: MOD7=1,MOD6=1,MOD5=1,MOD4=1,MOD3=1,MOD2=1,MOD1=1,MOD0=1 */
  setReg8(MTIM1MOD, 0xFF);
  /* MTIM1CLK: ??=0,??=0,CLKS1=0,CLKS0=1,PS3=0,PS2=1,PS1=1,PS0=0 */
  setReg8(MTIM1CLK, 0x16);
  (void)getReg8(MTIM1SC);              /* Overflow int. flag clearing (first part) */
  /* MTIM1SC: TOF=0,TOIE=1,TRST=0,TSTP=1,??=0,??=0,??=0,??=0 */
  setReg8(MTIM1SC, 0x50);              /* Int. flag clearing (2nd part) and timer control register setting */
}

Esse código é gerado dentro do arquivo MTIM3.c - nome também definido na Figura 3 - onde também é definida a função de tratamento de interrupção. Essa inicialização define os registradores:

-MTIM1MOD que define o módulo do contador. Na função pode-se verificar o valor 0xFF, que era o esperado, dado que foi escolhido o valor decimal de 255.

-MTIM1CLK que define o clock de referência para a contagem e o valor do PRESCALER.

-MTIM1SC que seta 0 para a variável de overflow do contador, habilita a interrupção para quando é detectada a variável de overflow, 0 para o reset e 1 para o stop (o que deixa evidente a necessidade de inicializar o contador).

A função MTIM3_Init() é chamada logo após a configuração do oscilador (que não será novamente reproduzida aqui), na função PE_low_level_init(), desse modo, na função principal main() do programa, quando é chamada a função PE_low_level_init() tanto o oscilador externo, quanto a inicialização do timer é configurada. Outra função importante, que também se encontra no arquivo MTIM3.c é a função de tratamento à interrupção, ISR(ONOFF_LED):

ISR(ONOFF_LED)
      {
        MTIM1SC_TOF = 0;
        PTFD_PTFD7 = ~PTFD_PTFD7;
      }

Ela é bastante simples. Com o seu primeiro comando, ela abaixa o nível lógico da flag de overflow do timer contador, permitindo a saída da interrupção. Através do seu segundo comando, é invertida o valor de saída do pino 7, como já havia sido feito antes.

É importante observar ainda que essa função é apontada pela tabela de vetor de interrupção que se encontra no arquivo Vector.c:

/* ISR name                               No. Address      Lvl Pri Name          Description */
...
Cpu_Interrupt,                       /* 0x45  0x00000114   -   -   ivVtpm1ch2    unused by PE */
Cpu_Interrupt,                       /* 0x46  0x00000118   -   -   ivVtpm1ovf    unused by PE */
ONOFF_LED,                           /* 0x47  0x0000011C   6   1   ivVmtim1      used by PE */
Cpu_Interrupt,                       /* 0x48  0x00000120   -   -   ivVtpm2ch0    unused by PE */
Cpu_Interrupt,                       /* 0x49  0x00000124   -   -   ivVtpm2ch1    unused by PE */

Como observado acima, a função ONOFF_LED se encontra na posição 0x47 do vetor de interrupção que aponta para o endereço 0x0000011C. No vetor é ainda observado o valor do level e da prioridade da interrupção. Por fim, é exibida a função principal (main()):

/* Including needed modules to compile this module/procedure */
#include "Cpu.h"
#include "Events.h"
#include "MTIM3.h"
/* Include shared modules, which are used for whole project */
#include "PE_Types.h"
#include "PE_Error.h"
#include "PE_Const.h"
#include "IO_Map.h"

void main(void)
{
  /*** Processor Expert internal initialization. ***/
  PE_low_level_init(); //Inclui a inicialização do Módulo Timer

  PTFDD = 0x80; // inicializa PTF7 como saída
  PTFD = 0;  // inicializa PTF com o valor 0

  MTIM1SC_TRST = 1;
  MTIM1SC_TSTP = 0;

  for(;;){}

}

No início, antes de inicializar a main(), observa-se todos os includes necessário para que os registradores possam ser setados através de comandos simplificados, além de configurações do microcontrolador sendo utilizado. Logo no início da main, a função PE_low_level_init() é chamada, onde é feita a configuração do relógio utilizado e do módulo Timer, como já explicado. Os dois comandos seguintes, já conhecidos, inicializam o pino que se encontra fisicamente conectado ao LED. É primeiramente inicializada a porta F como saída e ao pino 7 é então atribuído o valor lógico 0. Os dois comandos seguintes são novos. O primeiro, MTIM1SC_TRST se refere ao bit TRST do registrador MTIM1SC, e tem a função de resetar o contador. O segundo, MTIM1SC_TSTP, se refere ao bit TSTP do registrador MTIM1SC, e tem a função de deixar o contador ativo. Todos os registradores do módulo timer utilizado, assim como suas definições, se encontram no capítulo 18 do manual de referência: MCF51CN128 Integrated Microcontroller Reference Manual.

Parte 2: Início do projeto de interface serial RS-232

Parte referente à aula 10 A especificação física das conexões foi iniciada pelo outro integrante do grupo, que sugeriu o uso do CI MAX232 para sobrelevação de tensão. Será iniciada aqui a discussão da configuração da porta serial assíncrona do microcontrolador para comunicação com um computador.

Utilização da porta serial assíncrona do microcontrolador (SCI)

Inicialmente, como teste, foi inicializado o periférico SCI através do Processor Expert, como pode ser visto nas Figuras 4 e 5.

/media/Attachments/courseEA079_1S2010/Mped_5/scum.bmp

Figura 4: Obtenção do módulo SC1 no Processor Expert

/media/Attachments/courseEA079_1S2010/Mped_5/scdois.bmp

Figura 5: Configuração do Módulo SC1 no Processor Expert

Foi obtido um código de configuração da porta serial. Esse pode ser observado abaixo:

void SCI4_Init(void)
{
  /* SCI1C2: TIE=0,TCIE=0,RIE=0,ILIE=0,TE=0,RE=0,RWU=0,SBK=0 */
  setReg8(SCI1C2, 0x00);
  (void)getReg8(SCI1S1);
  (void)getReg8(SCI1D);
  /* SCI1S2: LBKDIF=1,RXEDGIF=1,??=0,RXINV=0,RWUID=0,BRK13=0,LBKDE=0,RAF=0 */
  setReg8(SCI1S2, 0xC0);
  /* SCI1BDH: LBKDIE=0,RXEDGIE=0,??=0,SBR12=0,SBR11=0,SBR10=0,SBR9=0,SBR8=0 */
  setReg8(SCI1BDH, 0x00);
  /* SCI1BDL: SBR7=0,SBR6=1,SBR5=0,SBR4=0,SBR3=0,SBR2=0,SBR1=0,SBR0=0 */
  setReg8(SCI1BDL, 0x40);
  /* SCI1C1: LOOPS=0,SCISWAI=0,RSRC=1,M=0,WAKE=0,ILT=0,PE=0,PT=0 */
  setReg8(SCI1C1, 0x20);
  /* SCI1C3: R8=0,T8=0,TXDIR=1,TXINV=0,ORIE=0,NEIE=0,FEIE=0,PEIE=0 */
  setReg8(SCI1C3, 0x20);
  /* SCI1C2: TIE=0,TCIE=0,RIE=0,ILIE=0,TE=0,RE=0,RWU=0,SBK=0 */
  setReg8(SCI1C2, 0x00);
}

Nele pode se observar que são feitas as configurações dos registradores do SCI que podem ser observadas no capítulo 13 - Serial Communication Interface (SCI) - da referência MCF51CN128RM.