Control de problemas MAX7301 GPIO Expander a través de SPI utilizando Arduino Uno R3

2

Estoy intentando escribir un controlador para controlar un expansor de puerto GP7 MAX1301 que se controlará a través de SPI.

He usado SPI anteriormente y es bastante simple, pero he estado trabajando en esto por unos días y no puedo obtener una respuesta del chip cuando intento leer y escribir en los registros.

He revisado detenidamente la hoja de datos y no puedo encontrar nada que me parezca una solución. Estoy 100% seguro de que las señales que estoy enviando son efectivamente recibidas por el chip, ya que he pegado algunas sondas de osciloscopio en las patas del chip.

Lo único que he notado es que ocasionalmente aparecerá una señal de 5 V en la línea MISO, a menudo donde me gustaría ver una señal que existe el tiempo suficiente para ser sincronizada. Sospecho que esta puede ser la raíz del problema.

En el MAX7301, Dout no es de alta impedancia y tiene que estar conectado a un búfer de tres estados externo. No creo que esté en un estado Z cuando quiero leerlo, pero ¿el búfer podría estar haciendo otra cosa?

Estaría inmensamente agradecido si alguien pudiera brindarme algunos consejos sobre cómo abordar el problema.

La hoja de datos MAX7301 se puede encontrar aquí

Mi código en la actualidad está abajo:

    /** 
 \mainpage Arduino / 2436W10003 SPI Comms.
 \file project5.ino
 \brief Control SPI comms. and display results on PC.
 \details Another time perhaps.
 \author
 \version 0.1
 \date 12/08/2013
 */

/*! SPI.h */
#include <SPI.h>

/*! Baud rate used in serial comms. between Arduino and PC */
#define SERIALSPEED 9600
/*! Pin number of SSSEL_GPIO */
#define SSEL_GPIO 2
/*! Pin number of SSEL_ADC */
#define SSEL_ADC 3

#define NOP 0x00


/**
 *  \brief Brief
 *  
 *  \param [in] void
 *  
 *  \return void
 *  
 *  \details Details
 */
void loop(void)
{
  int result;
  result = readGPIO(0x04);
  Serial.println(result, HEX);
}

/**
 *  \brief Brief
 *  
 *  \return Return_Description
 *  
 *  \details Details
 */
void setup(void)
{
  // Configure serial comms. with PC
  Serial.begin(SERIALSPEED);
  //Serial.print("Serial communiciations set up at %d baud.", 9600); // sort the %d thing out later

  // Configure GPIO pins
  pinMode(SSEL_GPIO, OUTPUT);
  pinMode(SSEL_ADC, OUTPUT);

  // Slave select pins active LOW, so set inactive HIGH
  digitalWrite(SSEL_GPIO, HIGH);
  digitalWrite(SSEL_ADC, HIGH);

  // Configure SPI
  SPI.setDataMode(SPI_MODE0);
  // SPI_CLOCK_DIV2 --> 128
  // 16 MHz / divider = 16 / 4 = 4MHz
  SPI.setClockDivider(SPI_CLOCK_DIV4);
  // MSBFIRST or LSBFIRST
  SPI.setBitOrder(MSBFIRST);
  SPI.begin();

  writeGPIO(0x04, 0x01);
  writeGPIO(0x04, 0x01);
}

/**
 *  \brief Brief
 *  
 *  \return void
 *  
 *  \details Details
 */
void writeGPIO(byte address, byte data)
{ 
  address &= ~0x80; // ensure bit 15 is cleared
  digitalWrite(SSEL_GPIO, LOW);

  SPI.transfer(0x04);
  SPI.transfer(0x01);

  digitalWrite(SSEL_GPIO, HIGH);
}

/**
 *  \brief Brief
 *  
 *  \return address
 *  
 *  \details Details
 */
byte readGPIO(byte address)
{
  byte result;

  // Ensure that the WRITE bit is set
  address |= 0x80;

  digitalWrite(SSEL_GPIO, LOW);

  // D15 to D8 contain R/W bit and register address
  SPI.transfer(address);
  // D7 to D0 discarded
  SPI.transfer(NOP);

  digitalWrite(SSEL_GPIO, HIGH);
  // Allow a few ns for MAX7301 register to fill up
  digitalWrite(SSEL_GPIO, LOW);

  // No useful data in MSByte
  SPI.transfer(NOP);
  // Results from register should be in LSbyte
  result |= SPI.transfer(NOP);

  digitalWrite(SSEL_GPIO, HIGH);

  return(result);
}
    
pregunta Mitchell

1 respuesta

1

Puede ser que la función writeGPIO elimine sus argumentos y solo escriba un valor de 0x01 en la dirección 0x04 . El uso de los argumentos de la función debería solucionar este problema:

void writeGPIO(byte address, byte data)
{
    address &= ~0x80; // ensure bit 15 is cleared
    digitalWrite(SSEL_GPIO, LOW);
    SPI.transfer(address); // use the address argument
    SPI.transfer(data);    // use the data argument
    digitalWrite(SSEL_GPIO, HIGH);
}

Sin embargo, también parece que el protocolo de 4 hilos del MAX7301 puede no ser necesariamente tan compatible con SPI como se esperaba. Por lo general, los datos se registran dentro y fuera de los registros de turno al mismo tiempo. El diagrama de tiempo en la página 8 muestra que los datos se registran en el dispositivo en DIN en el flanco ascendente de SCLK (modo SPI 0 o 2), pero que los datos se registran en el dispositivo en DOUT en el borde descendente de SCLK (SPI modo 1 o 3). Es posible que tenga mejor suerte con un software SPI dada esta diferencia. A continuación, proporcioné una implementación sencilla basada en el retraso, aunque no tengo acceso a un Arduino, por lo que no lo he probado.

//this function takes the place of SPI.transfer
byte transferMax7301Byte(byte data_out)
{
    byte current_bit, result;
    result = 0;
    //must clock each bit
    for(current_bit = 0; current_bit < 8; current_bit++)
    {
        //SCLK falling edge, MAX7301 changes output
        digitalWrite(SCLK_GPIO, LOW);
        //shift data from DOUT pin read into result
        result = (result << 1) | digitalRead(DOUT_GPIO);
        //9600 baud is about 104 microseconds per pulse
        //so wait half of that time between edges
        delayMicroseconds(52);
        //SCLK rising edge, Arduino changes output
        digitalWrite(SCLK_GPIO, HIGH);
        //shift data out of data_out onto DIN pin
        digitalWrite(DIN_GPIO, data_out & 0x80);
        data_out <<= 1;
        //wait the other half of the 104 microseconds
        delayMicroseconds(52);
    }
    //last falling edge of SCLK
    digitalWrite(SCLK_GPIO, LOW);
    //read last bit from DOUT pin
    result = (result << 1) | digitalRead(DOUT_GPIO);
    return result;
}

void writeGPIO(byte address, byte data)
{ 
    address &= ~0x80; // ensure bit 15 is cleared
    digitalWrite(SSEL_GPIO, LOW);

    transferMax7301Byte(address);
    transferMax7301Byte(data);

    digitalWrite(SSEL_GPIO, HIGH);
}

byte readGPIO(byte address)
{
    byte result;

    // Ensure that the D15 bit is set
    address |= 0x80;

    digitalWrite(SSEL_GPIO, LOW);

    // D15 to D8 contain R/W bit and register address
    transferMax7301Byte(address);
    // D7 to D0 discarded
    transferMax7301Byte(NOP);

    digitalWrite(SSEL_GPIO, HIGH);
    // Allow a few ns for MAX7301 register to fill up
    digitalWrite(SSEL_GPIO, LOW);

    // No useful data in MSByte
    transferMax7301Byte(NOP);
    // Results from register should be in LSbyte
    result |= transferMax7301Byte(NOP);

    digitalWrite(SSEL_GPIO, HIGH);

    return(result);
}
    
respondido por el multipleinterfaces

Lea otras preguntas en las etiquetas