I'm trying to write a driver to control a MAX7301 GPIO port expander that will be controlled via SPI.
I've used SPI before and it's pretty simple, but I've been working on this for a few days and I can't get a response from the chip when I try to read and write to registers.
I've pored over the datasheet and I can't find anything that strikes me as a solution. I am 100% confident that the signals I am sending are indeed received by the chip, as I've stuck a few oscilloscope probes on the chip's legs.
The one thing I have noticed is that occasionally a 5V blip will appear on the MISO line, often where I would like to see a signal that exists long enough to be clocked. I suspect this may be the root of the problem.
On the MAX7301, Dout is not high-impedance and has to be connected to an external tri-state buffer. I don't think it's in a Z state when I want to read it, but could the buffer be doing something else?
I would be immensely grateful if anybody could provide me with some advice on how to approach the problem.
The MAX7301 datasheet can be found here
My code at present is below:
/**
\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);
}