¿El reloj SPI se “estancó” en ATmega1284P?

1

Estoy intentando que las comunicaciones SPI funcionen en un ATmega1284P. Este es el código que estoy usando:

// clocked by external 12.000 MHz crystal, lfuse=0xce
#define F_CPU 12000000

#include <avr/io.h>

#define SPI_SCK PB7
#define SPI_MISO PB6
#define SPI_MOSI PB5
#define SPI_SS PB4
#define SPI_PORT PORTB
#define SPI_DDR DDRB
#define SPI_PIN PINB
//#include "spi.h"
//#include "serial.h"

void initUart()
{
#define BAUD 38400
#include <util/setbaud.h>
  UBRR0H = UBRRH_VALUE;
  UBRR0L = UBRRL_VALUE;
#if USE_2X
  UCSR0A |= _BV(U2X0);
#else
  UCSR0A &= ~_BV(U2X0);
#endif
  UCSR0B |= (_BV(RXEN0) | _BV(TXEN0));
  UCSR0C |= (_BV(UCSZ01) | _BV(UCSZ00));
}

void cOut(unsigned char c)
{
  while (!(UCSR0A & _BV(UDRE0)))
    ;
  UDR0 = c;
}

inline void spi_init()
{
  // set MISO as input
  SPI_DDR &= ~(_BV(SPI_MISO));
  // set MOSI and SCK as output
  SPI_DDR |= (_BV(SPI_SCK) | _BV(SPI_MOSI));
  // enable SPI, master mode, and SPI prescaler
  SPCR = (_BV(SPE) | _BV(MSTR) | _BV(SPR1) | _BV(SPR0));
//  SPCR = (_BV(SPE) | _BV(MSTR));
}

unsigned char spi_transact(unsigned char c)
{
  cOut('t');
  // put byte to transmit into buffer
  SPDR = c;
  cOut('+');
  // wait until the SPI timer has overflowed
  while (!(SPSR & _BV(SPIF)))
    ;
  cOut('T');
  // return the byte transferred in via SPI
  return SPDR;
}

int main()
{
  // disable JTAG for full access to port C
//  register unsigned char regTemp = MCUCR | _BV(JTD);
//  MCUCR = regTemp;
//  MCUCR = regTemp;

  initUart();
  SPI_DDR |= SPI_SS;
  spi_init();

//  sOut_P(CRLF);
  cOut('\r');
  cOut('\n');

//  SPI_PORT |= SPI_SS;
  cOut('1');
  spi_transact(0xa0);
  cOut('2');
  spi_transact(0);
  cOut('3');
  spi_transact(0);
  cOut('4');
  spi_transact(0x12);
  cOut('5');
  spi_transact(3);
  cOut('6');
  spi_transact(1);
  cOut('7');
  spi_transact(1);
  cOut('8');
  spi_transact(0x13);
  cOut('9');
//  SPI_PORT &= ~SPI_SS;
//  sOut_P(CRLF);
  cOut('\r');
  cOut('\n');
  cOut('!');

//  sOut("Clock reset\r\n");
}

Actualmente no tengo nada conectado realmente a los pines SPI, ya que estoy intentando ver si puedo hacerlo funcionar antes de conectarlo con el esclavo SPI.

Mi terminal emite "1t + T2t +" desde el UART, mostrando un bloqueo al esperar a que se establezca SPIF, pero si toco el final de un cable conectado a SCK, eventualmente pasa eso y completa la sesión SPI. ¿Por qué cargar SCK externamente hace que funcione, cuando se supone que el maestro genera internamente el reloj?

    

1 respuesta

4

No he verificado esto porque no tengo ningún hardware disponible, pero creo que veo el problema.

No estás inicializando la dirección del pin SS correctamente.

SPI_DDR |= SPI_SS;

establece el pin incorrecto (PB2). Debería ser

SPI_DDR |= _BV(SPI_SS);

con _BV () configurando el cuarto bit (SPI_SS = PB4 = 4).

En cuanto al extraño comportamiento que puede resultar de no configurar SS como salida.

  

Si SS se configura como una entrada, debe mantenerse alto para asegurar la operación del SPI maestro. Si el pin SS se mueve bajo por los circuitos periféricos cuando el SPI está configurado como maestro con el pin SS definido como entrada, el sistema SPI lo interpreta como otro maestro que selecciona el SPI como esclavo y comienza a enviarle datos.

Esto haría que su sistema se convierta en un esclavo SPI, por lo que se requiere que un reloj externo envíe más datos y active el siguiente SPIF. Al tocar el SCK, puede provocar una ondulación que actúa como un reloj.

    
respondido por el Rev1.0

Lea otras preguntas en las etiquetas