terça-feira, fevereiro 07, 2012

Display Gráfico Nokia 5110 - Parte 8: MSP430

Para encerrarmos nossas experiências com o display Nokia 5110, vamos conectá-lo ao Launchpad da Texas, que utiliza um microcontrolador da família MSP430.


O modelo específico que vamos usar é o MSP430G2231 que possui 2K de memória Flash, 128 bytes de Ram e 10 pinos de E/S digital. Os 2K de Flash, em uma arquitetura Von-Neuman, permitem colocar facilmente a nossa matriz de caracteres. Já os 128 bytes de Ram impedem de manter uma imagem da tela na memória.

Hardware

Como a Launchpad trabalha com 3,6V vamos abusar ligeiramente o display e conectá-lo diretamente. Vamos usar a USI (Universal Serial Interface) para gerar os sinais DIN e SCK, os demais sinais serão gerados por E/S digital. Ficamos portanto com as seguintes conexões entre o display e a Launchpad:
  • Vcc -> Vcc
  • Gnd -> Gnd
  • SCE -> P1.4
  • RST -> P1.0
  • D/C -> P1.1
  • DIN -> P1.6
  • SCK -> P1.5
  • LED -> Vcc através de um resistor de 100R
Software

Para sofisticar um pouco, vamos colocar duas imagens e uma barra indicando a leitura de temperatura feita pelo sensor interno do MSP430. O software foi feito usando o compilador IAR.

Como de costume, a parte mais complicada é iniciar corretamente os periféricos:
  • O watchdog precisa ser desligado (ou reiniciado periodicamente), já que é ativado no reset.
  • As entradas e saídas digitais precisam ter a direção programa, o resto das configurações podem ficar nos valores de reset.
  • A USI é bastante flexível, o que significa que tem vários registradores de configuração. Em primeiro lugar, precisamos acionar os pinos de SDO e SCLK, selecionar operação SPI master, habilitar a saída e deixar a operação suspensa.Isto é feito no registrador USICTL0.
  • O registrador USICTL1 deve ser programado com zero, para ativar o modo SPI.
  • O clock para a USI foi programado para SMCLK/8 no registrador USICKCTL.
  • A contagem de bits (USICNT) é iniciada com zero e a operação da USI é liberada no USICTL0.
  • Embora o MSP430G2231 possa gerar internamente um clock de até 16MHz, vamos trabalhar com 1MHz que é o valor calibrado na fábrica.
  • A programação do ADC para leitura da temperatura foi copiada do exemplo da Texas.
  • Para fazer a leitura periodicamente vamos usar o TimerA, alimentado pela base de tempo de 12KHz do MSP430.
void IniciaHw (void)
{
  // Programa entradas e saídas digitais
  P1SEL = 0;
  P1DIR = PIN_SCE | PIN_RESET | PIN_DC | PIN_SDIN | PIN_SCLK;
  P1OUT = PIN_SCE;
    
  // Programa a USI
  USICTL0 = USIPE6 | USIPE5 | USIMST | USIOE | USISWRST ;
  USICTL1 = 0;
  USICKCTL = USIDIV_2 | USISSEL_2;  // Clock = SMCLK/8 = 1/16 MHZ = 62,5 KHz, ativo low
  USICNT = 0;
  USICTL0 &= ~USISWRST;
  
  // retira o reset do LCD
  P1OUT = PIN_SCE | PIN_RESET;

  // Ligar o DCO, vamos trotar a 1MHz
  BCSCTL1 = CALBC1_1MHZ;
  DCOCTL  = CALDCO_1MHZ;
  BCSCTL2 = 0;
  
  // Configura o ADC para ler o sensor de temperatura
  ADC10CTL1 = INCH_10 + ADC10DIV_3;         // Temp Sensor ADC10CLK/4
  ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE;
  
  // Configura ACLK p/ 6 KHz
  BCSCTL1 |= DIVA_1;                        // ACLK/2
  BCSCTL3 |= LFXT1S_2;                      // ACLK = VLO / 2
}
Feita a programação da USI, para enviar um byte basta colocá-lo em USISRL e carregar 8 em USICNT. A USI se encarrega de gerar o clock e deslocar os bits. O fim da transmissão é sinalizado pelo bit USIIFG no registrador USICTL1.
// Envia um byte para o controlador do display
// dc:   LCD_CMD ou LCD_DAT
// data: byte a enviar
void LcdWrite(byte dc, byte data)
{
  // Seleciona dado ou comando
  if (dc == LCD_DAT)
    P1OUT |= PIN_DC;
  else
    P1OUT &= ~PIN_DC;
  
  // Seleciona o display
  P1OUT &= ~PIN_SCE;
  
  // Envia o byte
  USICTL0 |= USIOE;
  USISRL = data;
  USICNT = 8;
  while ((USICTL1 & USIIFG) == 0)
    ;

  // Desliga a seleção
  P1OUT |= PIN_SCE;
}
A leitura da temperatura é feita disparando a conversão e deixando o processador parado (low power mode 0) enquanto ela é concluída. A instrução __bis_SR_register liga (coloca em 1) bits do registrador de status (SR). No caso são ligados os bits que param o processador e habilita interrupções. Quando uma interrupção ocorre, este valor do SR é salvo na pilha e o processador é acordado. A rotina de interrupção usa a instrução __bic_SR_register_on_exit para limpar (colocar em 0) bits da cópia do SR que está na pilha. Quando a rotina retorna, é restaurado o SR alterado, o que no caso significa que o processador estará novamente rodando.
// Faz uma leitura de temperatura
void LeTemperatura (void)
{
  ADC10CTL0 |= ENC + ADC10SC;
  __bis_SR_register(CPUOFF + GIE);    // dorme em LPM0 até concluir leitura
  temperatura = ADC10MEM;
}

// Trata interrupção do ADC
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR (void)
{
  __bic_SR_register_on_exit(CPUOFF);  // Retorna ao modo ativo
}
No lado do timer, é usado o modo de "contagem para cima", onde ele conta de 0 até o valor escrito em TACCR0. Ao atingir o valor, uma interrupção é gerada. Novamente é usado o recurso de economia de energia; neste caso paramos mais partes do MSP430 usando o low power mode 3.
// Dorme por 200 mseg
void Dorme (void)
{
  TACCR0 = 1200;                         // 200 ms
  TACTL = TASSEL_1 | MC_1 | TAIE;        // ACLK, Up mode.  
  __bis_SR_register(LPM3_bits + GIE);    // dorme em LPM3 até timer interromper
}

// Trata interrupção do timer
// Timer A0 interrupt service routine
#pragma vector=TIMERA1_VECTOR
__interrupt void Timer_A (void)
{
  TACTL = TASSEL_1;                       // Para o timer
  __bic_SR_register_on_exit(LPM3_bits);   // Retorna ao modo ativo
}
O nosso programa principal fica assim:
int main( void )
{
  // Desliga Watchdog
  WDTCTL = WDTPW + WDTSSEL + WDTHOLD;

  // Inicia o hardware
  IniciaHw();
  LcdInitialise();
 
  // Mostra a nossa tela inicial
  LcdClear();
  LcdWriteString ("DQSoft", 0, 3);
  LcdWriteImg (invasor1, 30, 16, 11, 8);
  LcdWriteImg (invasor2, 51, 16, 8, 8);

  // Loop principal
  for (;;)
  {
    Dorme ();
    LeTemperatura ();
    LcdBarraHoriz(0, 40, LCD_DX, 0);
    LcdBarraHoriz(0, 40, (int) (temperatura >> 4), 1);
  }
}
O projeto completo está nos arquivos do blog (veja lá no alto à direita) no arquivo Nokia5110_MSP430.zip.

4 comentários:

Jucimar Antunes Cabral disse...

Bom dia
Qual sua versão do IAR?
Pois não consigo abrir na minha versão (4,2)
Eu teria como modificar para poder abrir?

Daniel Quadros disse...

Acho que usei a 5.30. Não tenho certeza se 4.2 suporta o MSP430G que é usado na Launchpad. De qualquer forma, o jeito é criar um novo workspace / projeto com a sua versão, acertar a configuração para a Launchpad e incluir os meus fontes. Outra opção é baixar a versão atual do site da IAR (http://supp.iar.com/Download/SW/?item=EW430-KS4).

NOME disse...

Ola..Boa Noite..Gostaria de Saber se este projeto com o MSP430..TEM video..? Obrigada!!

Daniel Quadros disse...

Não fiz nenhum vídeo deste projeto com o MSP430. O mais próximo foi um vídeo do display ligado a um Arduino: http://www.youtube.com/watch?feature=player_embedded&v=xO05Rs3qrdo