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:
Postar um comentário