Jump to content
43oh

Making SPI work


Recommended Posts

I'm attempting to talk to a digipot over SPI with energia. The pot in question is a microchip mcp4261 (http://ww1.microchip...eDoc/22059b.pdf).

 

To communicate with it, you pull the CS pin active (low), send it a 2 byte command then pull the CS pin back high. Without quoting the entire the data sheet, the basic command sequence is a 4 bit register address, 2 bit command, and 9 data bits. When you issue the read command, it is supposed to return 9 bits of data (the value of the register).

 

I've bread boarded this up using the SPI examples with the following layout:

 

CS -> P2.0

SCK -> P1.5

SDI -> P1.7

SDO -> P1.6

 

I also applied VDD/VSS across P1A/P1B and connected the wiper up to P1.0.

 

Here is the code I'm using to talk to the pot:

/*
SCP1000 Barometric Pressure Sensor Display

Shows the output of a Barometric Pressure Sensor on a
Uses the SPI library. For details on the sensor, see:
http://www.sparkfun.com/commerce/product_info.php?products_id=8161
http://www.vti.fi/en/support/obsolete_products/pressure_sensors/

This sketch adapted from Nathan Seidle's SCP1000 example for PIC:
http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip

Circuit:
SCP1000 sensor attached to pins 6, 7, 10 - 13:
DRDY: pin 6
CSB: pin 8
MOSI: pin 14/15
MISO: pin 15/14 * need to level convert this
SCK: pin 7

created 31 July 2010
modified 14 August 2010
by Tom Igoe

modified 2 May 2012
Rick Kimball - changed pin # for msp430

modified 23/11/12
Matt Beals - adapted for MCP4261

*/
const int WIPER0	 = 0x00;
const int WIPER0_default = 0x02;
const int WIPER1 =		 0x01;
const int WIPER1_default = 0x03;
const int TCON = 0x04;
const int STATUS = 0x05;
const int DATA0 = 0x06;
const int DATA1 = 0x07;
const int DATA2 = 0x08;
const int DATA3 = 0x09;
const int DATA4 = 0x0A;
const int DATA5 = 0x0B;
const int DATA6 = 0x0C;
const int DATA7 = 0x0D;
const int DATA8 = 0x0E;
const int DATA9 = 0x0F;

//Command bits
const byte READ = 0b11;
const byte WRITE = 0b00;
const byte UP = 0b01;
const byte DOWN = 0b10;

// the sensor communicates using SPI, so include the library:
#include <SPI.h>
#include <TimerSerial.h>

TimerSerial TS;


// pins used for the connection with the sensor
// the other you need are controlled by the SPI library):

const int chipSelectPin = 8; // P2.0
unsigned int stat;
byte i = 0;

int sensorPin = A0; // select the input pin for the potentiometer
int sensorValue = 0;

void setup() {
TS.begin(9600);

// start the SPI library:
SPI.begin();

// initialize the data ready and chip select pins:
pinMode(chipSelectPin, OUTPUT);
delay(100);

}


void loop() {

stat = readRegister(WIPER0);
sensorValue = analogRead(sensorPin);

TS.print("Sensor Value: ");
TS.print(sensorValue);
TS.println(" ");

sendData(WIPER0, i);
i += 10;
if(i > 257){
i = 0;
}

delay(10000);
TS.println(" ");
}

//Read from or write to register
unsigned int readRegister(int Register) {
int inByte = 0;		 // incoming byte from the SPI
unsigned int result = 0; // result to return

TS.print("Reading Register: ");
TS.print(Register);

// now combine the register address and the command
int dataToSend = (Register << 12) | (READ << 10);
TS.print("\t Sending Code : ");
TS.print(dataToSend,BIN);

//Pull pin active, write the command, then pull pin inactive
digitalWrite(chipSelectPin, LOW);
result = SPI.transfer(dataToSend);
delay(10);
digitalWrite(chipSelectPin, HIGH);

TS.print("\t Reply: ");
TS.print(result, BIN);
TS.println(" ");

return(result);
}


void stepWiperUP(int Register){
int dataToSend = 0b00000100 | (Register << 4);
SPI.transfer(dataToSend);
delay(10);
digitalWrite(chipSelectPin, HIGH);
}


void stepWiperDOWN(int Register){
int dataToSend = 0b00001000 | (Register << 4);
SPI.transfer(dataToSend);
delay(10);
digitalWrite(chipSelectPin, HIGH);
}


void sendData(int Register, byte value) {

//4 bit register address needs to be first in 16 bit packet
// now combine the register address and the command into one byte:
int dataToSend = (Register << 12) | (WRITE << 10) | value;

TS.print("Writing Register ");
TS.print(Register);
TS.print(" with value: ");
TS.print(value);
TS.print(" Sending Code: ");
TS.print(dataToSend,BIN);
TS.println(" ");

digitalWrite(chipSelectPin, LOW);
SPI.transfer(dataToSend); //Send register location
delay(10);
digitalWrite(chipSelectPin, HIGH);
}

 

 

When I run this, this is the output I get:


Reading Register: 0 Sending Code : 110000000000 Reply: 11111111
Sensor Value: 574
Writing Register 0 with value: 218 Sending Code: 11011010

Reading Register: 0 Sending Code : 110000000000 Reply: 11111111
Sensor Value: 574
Writing Register 0 with value: 228 Sending Code: 11100100

 

From this, I can see that the commands I am writing to the pot follow the format specified in the datasheet, and that I am getting a reply back from the pot. If I pull power to the pot, swap MISO/MOSI lines, kill the clock, etc... this value goes to 0...so I'm fairly certain the connection side of the communication is fine. However, the reply should be changing with each iteration, as each step advances the wiper by 10 steps...which should also show up on the ADC (Sensor Value). I've even tried swapping the endianess with no luck.

 

Has anyone used the SPI library with success? Any hits or tips or things I can check?

Link to post
Share on other sites

SPI.transfer only transfers 8 bits. This is what I'm using to transfer a 16 bit value to a DAC.

 

void SPIWrite(int value){
 // value is 16 bits

 // take the LE ( SS ) pin high to inhibit data latching:
 digitalWrite(latchEnablePin, HIGH);
 MSB = highByte(value);
 LSB = lowByte(value);

 SPI.transfer(MSB);
 SPI.transfer(LSB);

 // take the LE ( SS ) pin low to latch the data:
 digitalWrite(latchEnablePin, LOW);
}

Link to post
Share on other sites

There is still something goofy going on. Even once I fixed that, it's still not working. I've even tried the very simple case where I write the one byte "step" command explicitly, and am still seeing no response. I think I'm going to have to wait until I can hook it up to a scope to verify the communication.

Link to post
Share on other sites

Well I fixed it. I believe the big issue was using signed ints where I should have been using unsigned ints, which was screwing up the bit shifts when I would shift over by a full byte.

 

In case anyone wants to use this device in the future, here is a working set of functions for it. There is more functionality left in the chip, but this covers the main register access and sweep functions.

 


/*
CS -> P2.0
SCK -> P1.5
SDI -> P1.7
SDO -> P1.6
*/

const unsigned int WIPER0 = 0x00;
const unsigned int WIPER0_default = 0x02;

const unsigned int WIPER1 = 0x01;
const unsigned int WIPER1_default = 0x03;

const unsigned int TCON = 0x04;
const unsigned int STATUS = 0x05;

const unsigned int DATA0 = 0x06;
const unsigned int DATA1 = 0x07;
const unsigned int DATA2 = 0x08;
const unsigned int DATA3 = 0x09;
const unsigned int DATA4 = 0x0A;
const unsigned int DATA5 = 0x0B;
const unsigned int DATA6 = 0x0C;
const unsigned int DATA7 = 0x0D;
const unsigned int DATA8 = 0x0E;
const unsigned int DATA9 = 0x0F;

//Command bits

const byte READ = 0b11;
const byte WRITE = 0b00;
const byte UP = 0b01;
const byte DOWN = 0b10;

const byte chipSelectPin = 8;

// the sensor communicates using SPI, so include the library:
#include <SPI.h>
#include <TimerSerial.h>

TimerSerial TS;

void setup() {

//Setup the software UART
TS.begin(9600);

//Enable the CS pin as an output
pinMode(chipSelectPin, OUTPUT);

// start the SPI library:
SPI.begin();
delay(100);

}

void loop() {

}


/*========= Write to device register and read result ======================*/
unsigned int pushCommand(unsigned int Register, unsigned int command, unsigned int value) {

unsigned int COMMAND_MOSI;
unsigned int COMMAND_MISO;
unsigned int DATA_MOSI;
unsigned int DATA_MISO;
unsigned int packet;

//Format full 2 bit packet into one int to handle overlap from 10 bit data
packet = (Register << 12) | (command << 10) | value;

//Chop packet into command and data bits
COMMAND_MOSI = (packet & 0xFF00) >> 8;
DATA_MOSI = (packet & 0xFF);

//Enable chip select, write two bits, read two bits, then disable CS
digitalWrite(chipSelectPin, LOW);
COMMAND_MISO = SPI.transfer(COMMAND_MOSI); //Send command byte
DATA_MISO = SPI.transfer(DATA_MOSI); //Send the data byte
digitalWrite(chipSelectPin, HIGH);

//reassemble and return the returned bytes
return (COMMAND_MISO << 8) | DATA_MISO;
}

/*========= Read value in a register ==========================*/
unsigned int readRegister(unsigned int Register){
return pushCommand(Register,READ,0);
}

/*======== Write to a register ============================*/
unsigned int writeRegister(unsigned int Register, unsigned int value){
return pushCommand(Register,WRITE,value);
}

/*======== Step a register n steps up in order ====================*/
//The device supports sequential writing, so we can sweep the wiper up or down
//at the clock frequency
byte stepUP(unsigned int Register, unsigned int steps){

byte COMMAND_MOSI = (Register << 4) | (UP << 2); //Format command byte
byte COMMAND_MISO = 1; //Preset "success" to 1

//Cycle CS, write and read to/from Bus
digitalWrite(chipSelectPin, LOW);
for(int i=0; i<steps; i++){
COMMAND_MISO &= (SPI.transfer(COMMAND_MOSI) & 2) >> 1; //Issue the step command 'steps' times
}
digitalWrite(chipSelectPin, HIGH);

return COMMAND_MISO;
}

/*============ Step a register n steps down in order ====================*/
byte stepDOWN(unsigned int Register, int steps){
byte COMMAND_MOSI = (Register << 4) | (DOWN << 2);
byte COMMAND_MISO = 1;

digitalWrite(chipSelectPin, LOW);
for(int i=0; i<steps; i++){
COMMAND_MISO &= (SPI.transfer(COMMAND_MOSI) & 2) >> 1;
}
digitalWrite(chipSelectPin, HIGH);
return COMMAND_MISO;
}

Link to post
Share on other sites

No problem. Hopefully my 3 days of fighting will help someone else hitting the same problem in the future.

 

Doesn't your bike's PCM also set mixture off the MAP? It might be better to intercept the input signal to the coil and add a delay/advance circuit there. It would simplify the response quite a bit.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...