segunda-feira, dezembro 30, 2013

Conectando uma EEProm ao MSP430 - 93C66

Vamos ver neste post uma outra opção de memória EEProm para usar com a Launchpad. A 93C66 é uma memória um pouco mais esquisita que a 24C256, mas pode ser encontrada por preços menores. A comunicação com o microcontrolador utiliza um outro protocolo serial, o SPI.

A memória 93C66 possui 4K bits, que podem ser acessados como 256 posições de 16 bits ou 512 posições de 8 bits (vamos usá-la aqui no modo 16 bits). O datasheet (93C66.pdf) está nos arquivos do blog.

O protocolo SPI utiliza quatro sinais para a comunicação: SCLK (clock), SS (seleção do slave), MISO (dado do slave para o master) e MOSI (dado do master para o slave). O SPI permite que sejam feitas simultaneamente duas transferências de bits, uma em cada sentido.




O protocolo SPI possui quatro modos de clock (variando a posição de repouso e a borda para a transferência de dados). A 93C66 suporta um subconjunto do SPI denominado Microwire. O Microwire suporta somente um dos modos de clock e opera em half-duplex (transfere somente em um sentido de cada vez). Os diagramas abaixo mostram a leitura e gravação na 93C66




Um detalhe importante é que normalmente o protocolo SPI utiliza um sinal SS negado (nível baixo seleciona o slave), mas a 93C66 utiliza um sinal SS normal (nível alto seleciona).

A mesma USI do MSP430G2231 que usamos para comunicar por I2C no post anterior pode ser programada para operar como SPI.

Novamente o hardware é simples:


As rotinas de leitura e gravação e o programa de teste ficam:
#include "io430.h"

typedef unsigned char  byte;
typedef unsigned int   word;

// definições dos pinos de E/S no port 1
#define  LED        0x01
#define  CS         0x10
#define  SDI        0x80

static void EEProm_WriteEnable (void);
static void EEProm_Write (word ender, word dado);
static word EEProm_Read (word ender);
static void WriteSPI (byte dado);
static word ReadSPI (void);
static void delay (void);

int main( void )
{
    word i;
    word dado;
    
    // Stop watchdog timer to prevent time out reset
    WDTCTL = WDTPW + WDTHOLD;

    // Programa entradas e saídas
    P1SEL = 0;
    P1DIR = (byte) ~SDI;     // apenas SDI é entrada
    P1OUT = 0;

    // Alimentação já deve estar estável, vamos ligar o DCO
    BCSCTL1 = CALBC1_1MHZ;
    DCOCTL  = CALDCO_1MHZ;

    // Programa USI
      // Clock = SMCLK/2 = 1/2 MHZ = 500 KHz, ativo low
    USICKCTL  = USIDIV0 | USISSEL1 | USICKPL | USISWRST;
      // Habilitar pinos, MSB first, Master
    USICTL0 = USIPE7 | USIPE6 | USIPE5 | USIMST;
      // Modo SPI
    USICTL1 = 0;
      // 8 bit shift register
    USICNT = 0;
      // Libera USI para operação
    USICKCTL  &= ~USISWRST;

    // Permite a gravação
    EEProm_WriteEnable ();
    
    // grava dados de teste
    for (i = 0; i < 256; i++)
      EEProm_Write (i, (i << 8) | i);
    
    // Testa continuamente a leitura
    while (1)
    {
      for (i = 0; i < 256; i++)
      {
          dado = EEProm_Read (i);
          if (dado != ((i << 8) | i))
          {
            P1OUT |= LED;
            while (1)
              ;
          }
      }
    }
}

// habilita escrita na EEProm
static void EEProm_WriteEnable (void)
{
  P1OUT |= CS;
  delay ();
  WriteSPI (0x04); 
  WriteSPI (0xFF);
  delay ();
  P1OUT &= ~CS;
  delay ();
}


// escreve na EEProm
static void EEProm_Write (word ender, word dado)
{
  // Escrita
  P1OUT |= CS;
  delay ();
  WriteSPI (0x05); 
  WriteSPI (ender);
  WriteSPI (dado >> 8);
  WriteSPI (dado & 0xFF);
  delay ();
  P1OUT &= ~CS;
  delay ();

  // Espera concluir
  P1OUT |= CS;
  delay ();
  while ((P1IN & SDI) == 0)
    ;
  delay ();
  P1OUT &= ~CS;
  delay ();
}

// le da EEProm
static word EEProm_Read (word ender)
{
  word dado;
  
  P1OUT |= CS;
  delay ();
  WriteSPI (0x06); 
  WriteSPI (ender);
  dado = ReadSPI ();
  delay ();
  P1OUT &= ~CS;
  return dado;
}

static void WriteSPI (byte dado)
{
  // Envia o byte
  USISRL = dado;
  USICTL0 |= USIOE;
  USICNT = 8;
  
  // espera fim da transferência
  while ((USICTL1 & USIIFG) == 0)
    ;
}

static word ReadSPI (void)
{
  byte d1, d2;
  
  // Dispara a recepção de 1 bit (dummy)
  USISRL = 0;
  USICTL0 &= ~USIOE;
  USICNT = 1;
  
  // Aguarda receber
  while ((USICTL1 & USIIFG) == 0)
    ;

  // Dispara a recepção do byte mais significativo
  USISRL = 0;
  USICTL0 &= ~USIOE;
  USICNT = 8;
  
  // Aguarda receber
  while ((USICTL1 & USIIFG) == 0)
    ;
  d1 = USISRL;

    // Dispara a recepção do byte menos significativo
  USISRL = 0;
  USICTL0 &= ~USIOE;
  USICNT = 8;
  
  // Aguarda receber
  while ((USICTL1 & USIIFG) == 0)
    ;
  d2 = USISRL;
  
  return (d1 << 8) | d2;
}

// uma pausa curta (e grosseira)
static void delay (void)
{
  int i;
  for (i = 0; i < 100; i++)
    ;
}

Nenhum comentário: