Microcontroladores: Protocolos SPI

Este artigo foi criado com o intuito de apresentar o protocolo SPI aplicado à comunicação entre microcontroladores e periféricos. Como interface será usada um a aplicação feita em Visual Basic.

Protocolos SPI

Visto os recursos disponíveis num microcontrolador serem limitados, por vezes há necessidade de os expandir. Assim, existem circuitos integrados com as mais variadas funções: memórias EEPROM, shift registers, conversores A/D… Para se poder comunicar com estes periféricos é necessário um protocolo de comunicação para que “ambas as partes se entendam”. Dos muitos protocolos disponíveis, um que foi massivamente adoptado para comunicação entre microcontroladores e periféricos externos foi o SPI (Serial Peripheral Interface).

O protocolo SPI é um protocolo série que permite transmissão síncrona bidireccional de 8 bits.

O SPI necessita que exista um master que controle o relógio. Visto o SPI ser bidireccional, o master pode enviar ou receber informação dos slaves, mas este é que irá ditar quem envia ou quem recebe.

Para determinar o destinatário da informação é necessário uma ligação directa a cada um dos slaves, que será a ligação que conecta os pinos CS (Chip Select). Assim, quando a informação tiver como destinatário o slave 1, o pino CS1 terá que ser activado para que este aceite a informação.

Microcontroladores

Microcontroladores: protocolo SPIPara demonstrar a aplicação deste protocolo será usado um microcontrolador da Microchip (PIC18F2580) e uma DAC (MCP4921). Uma DAC é um dispositivo que converte um sinal digital para analógico (Digital-to-Analog Conversion) , a DAC MCP4921 usa o protocolo SPI para receber a informação digital (8 bits) proveniente do microcontrolador e converte a informação recebida numa tensão analógica.

A DAC usada recebe a informação pelo pino SDI e embora o SPI permita que a comunicação seja bidireccional, não é possível enviar informação da DAC para o microcontrolador.

O comando de escrita da DAC consiste em 16 bits. Nestes 16 bits estará informação relativa ao modo de operação e aos dados. Os primeiros 4 bits dizem respeito ao modo de operação, os 12 bits restantes correspondem ao valor da tensão a converter.

Comandos de escrita
Bit 15Bit 14Bit 13Bit 12Bit 11Bit 10Bit 9Bit 8
A/BBUFGASHDND11D10D9D8
Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0
D7D6D5D4D3D2D1D0

A fórmula de conversão da DAC é a seguinte:

Vout=VREF GDN / 2N

A tensão de referência usada foi de 4.096 V. Assim, para um a tensão de 3,265 V é necessário que os 12 bits menos significativos representem o número 3265, ou seja:

D11D10D9D8D7D6D5D4D3D2D1D0
110011000001

As funções que permitem que os registos sejam configurados são disponibilizadas pela microchip. Assim, não será objectivo deste artigo explicar como as construir, mas sim como as usar, tal como aconteceu nos artigos relacionados com microcontroladores das edições anteriores.

Para começar é necessário importar os protótipos das funções SPI.

#include <p18cxxx.h>
#include <math.h>
#include "usart_funcs.h"
#include "function.h"
#include <spi.h>

Antes de começar a usar os recursos do microcontrolador é necessário activar todos os módulos que serão usados. Assim, activam-se as interrupções, as ADCs e define-se o tipo de saída da porta usada com o Chip Select.

void main(void) {
  unsigned char dac_val1, dac_val2, dac_val3;
  unsigned int node1,node3,node2,aux;

  //Enable interrupts
  INTCONbits.GIE = 1;
  INTCONbits.PEIE = 1;
  // Enable interrupt priority feature
  INTCONbits.IPEN = 1;
  // GIEH must be set in order to get access to low priority interrupts
  INTCONbits.GIEH = 1;
  INTCONbits.GIEL = 1;

  adcInit();
  TRISAbits.TRISA4=0; //PORTA4->output

Activa-se de seguida a USART que será usada para comunicar com o PC e, finalmente, o módulo SPI.

  //SYNC=0,BRGH=1,BRG16=0
  //fosc=40Mhz,baudrate=115200-->spbrgh=21
  OpenUSART(USART_TX_INT_OFF
      & USART_RX_INT_OFF & USART_ASYNCH_MODE
      & USART_EIGHT_BIT & USART_CONT_RX
      & USART_BRGH_HIGH, 21);
  OpenSPI(SPI_FOSC_16, MODE_00, SMPMID);

O programa irá aguarda por uma ordem vinda do PC, via USART. Quando for recebido algo pela USART o bit RCIF do registo PIR1bits ficará a 1.

Assim:

  LATAbits.LATA4=1;
  while(1) {
    if(PIR1bits.RCIF) {
      switch (Re()) {
        case 's':

Caso a informação recebida seja o carácter s, então os próximos bytes a serem recebidos dizem respeito ao valor que se pretende converter.

          dac_val1=Re();
          dac_val2=Re();
          dac_val3=Re();
          dac_val1=convert_to_hex( dac_val1);
          dac_val2=convert_to_hex( dac_val2);
          dac_val3=convert_to_hex( dac_val3);
          aux=0;
          aux=dac_val2;
          aux=aux<<4;
          aux=aux|dac_val3;

Tendo em conta que os primeiros 4 bits dos 16 que serão enviados para a DAC dizem respeito ao modo de funcionamento, então faz-se uma máscara com o byte mais significativo para poder concatenar com os 4 bits de configuração.

          LATAbits.LATA4 = 0;
          WriteSPI(0b01110000 | dac_val1);

Os outros 2 bytes recebidos serão concatenados entre si para que se possam enviar para a DAC. De notar que antes de enviar qualquer informação a porta A4 foi colocada a zero para activar o CS da DAC. Embora possa ser contraditório, o CS da DAC é activado quando este estiver com o valor lógico 0

          WriteSPI(aux);
          LATAbits.LATA4 = 1;
          break;

Se na vez de se ter recebido inicialmente o carácter s, se se tiver recebido o carácter r então significa que se pretende ler o valor da ADC0, que faz parte do microcontrolador.

        case 'r':
          Wr(adc_read(0));
          break;

Se o carácter recebido não for nem o s nem o r, não se executa nada.

        default: Putsr("\r parametro incorrecto\r");
          break;
      }
    }
  }
}

Assim se termina o programa para o microcontrolador.