Help with SPI programming

Hi I have a problem with the ADXL345, I want to ask you how do you write the set up into the registers (I am using SPI), because I just noticed that all this time I have been just declaring it as global variables.
`#define ADXL345_DEVICE 0x53;
// Global variables
values <- [0,0,0,0,0,0,0,0,0,0];
x <- 0;
y <- 0;
z <- 0;

//Registers
DATA_FORMAT <-0x31;
DATAX0 <- 0x32; //X-Axis Data 0
DATAX1 <- 0x33; //X-Axis Data 1
DATAY0 <- 0x34; //Y-Axis Data 0
DATAY1 <- 0x35; //Y-Axis Data 1
DATAZ0 <- 0x36; //Z-Axis Data 0
DATAZ1 <- 0x37; //Z-Axis Data 1
//Constants
const ADXL345_DEVICE = 0x53;
const POWER_CTL = 0x2D; // Power control register
//program start
hardware.spi257.configure(SIMPLEX_TX|SIMPLEX_RX|LSB_FIRST|CLOCK_IDLE_HIGH|CLOCK_2ND_EDGE, 500);
hardware.spi189.configure(CLOCK_IDLE_LOW, 500);`

I also have the CS to pin 1, GND <- GND, VCC <- 3V3, SDO <- PIN2, SDA<-PIN7, SCL<-PIN5.

Those pin connections look right, so all you probably need is functions to read and write registers:

`hardware.spi257.configure(CLOCK_IDLE_HIGH|CLOCK_2ND_EDGE, 500);
hardware.pin1.configure(DIGITAL_OUT);
hardware.pin1.write(1); // nCS high by default

function adxl345_write(reg, value) {
// See ADXL345 datasheet figure 37
hardware.pin1.write(0); // set nCS low
// R/nW=0 MB=0 so first byte is just the register number
hardware.spi257.write(reg.tochar() + value.tochar());
hardware.pin1.write(1); // nCS back high again
}

function adxl345_read(reg) {
hardware.pin1.write(0);
// R/nW=1 MB=0, second byte doesn’t matter
local ret = hardware.spi257.write((reg+0x80).tochar() + " ")
hardware.pin1.write(1);
return ret[1];
}`

Peter

Thanks so that is how you access the regiters, also do you think i will need an interrupt line?

Well, what are you trying to make? If the imp is going to be reading the registers continuously, then you won’t need an interrupt line. If you want the accelerometer to mostly get on with stuff by itself, and only tell the imp when something exceptional happens, then you’ll need an interrupt line. If you want the accelerometer to wake the imp up from deep sleep when something exceptional happens (for instance, if you care about the power consumption of this device), then you’ll need an interrupt line and it needs to be on the imp’s pin1 (so you’d have to move nCS to pin8 or pin9).

Peter

Well technically I just want to read continuously data so that should help, since you told me how to write to a register and read from them I guess I should be able to finish this little project. Thanks

also i dont really understand the way you write to it, so you put the hex for the address first and then the hex value you want into the register?
function adxl345_write(reg, value) { // See ADXL345 datasheet figure 37 hardware.pin1.write(0); // set nCS low // R/nW=0 MB=0 so first byte is just the register number hardware.spi257.write(reg.tochar(register address) + value.tochar(what goes into address)); hardware.pin1.write(1); // nCS back high again }

Yes, to write (for instance) 0x14 into register 0x31, you’d do:

adxl1345_write(0x31, 0x14);

If you want to write (or read) several registers, you need to make several calls to adxl1345_write (or adxl1345_read).

You don’t need to change the insides of functions adxl1345_write or adxl1345_read. Your code should just be calling them as-is.

Peter

I see, so that is how it goes…after the function I just call it…now I can set up the registers and will probably be able to finally read some data! Thanks for explaining this to me…also there is something I cant figure out what is that ox80 and that + " " in the part of: and it also says that ret index 1 does not exist
function adxl345_read(reg) { hardware.pin1.write(0); // R/nW=1 MB=0, second byte doesn't matter local ret = hardware.spi257.write((reg+0x80).tochar() + " ") hardware.pin1.write(1); return ret[1];}
Here is my new updated code:
`#define ADXL345_DEVICE 0x53;

local values = [0,0,0,0,0,0,0,0,0,0];
//pin 1 is CS and should be driven high unless transmitting
hardware.pin1.configure(DIGITAL_OUT);
hardware.pin1.write(1); // nCS high by default

//program start
hardware.spi257.configure(MSB_FIRST|CLOCK_IDLE_HIGH|CLOCK_2ND_EDGE, 500);

function adxl345_write(reg, value) {
// See ADXL345 datasheet figure 37
hardware.pin1.write(0); // set nCS low
// R/nW=0 MB=0 so first byte is just the register number
hardware.spi257.write(reg.tochar() + value.tochar());
hardware.pin1.write(1); // nCS back high again
}
adxl345_write(0x2D, 0x08);
adxl345_write(0x31, 0x01);
adxl345_write(0x38, 0x00);

function adxl345_read(reg) {
hardware.pin1.write(0);
// R/nW=1 MB=0, second byte doesn’t matter
local ret = hardware.spi257.write((reg + 0x80).tochar() + " ")
hardware.pin1.write(1);
return ret;
}
local x = adxl345_read(0X32 + 0x33);
local y = adxl345_read(0x34 + 0x35);
local z = adxl345_read(0x36 + 0x37);
//x = (values[1] << 8 | values[0]);
//y = (values[3] << 8 | values[2]);
//z = (values[5] << 8 | values[4]);
server.log(x);
server.log(y);
server.log(z);`

Whoops, the “spi.write” in adxl345_read should have been “spi.writeread” – sorry about that. That should fix the “index 1 does not exist” problem.

After that it should just be:

local x = (adxl345_read(0x33) << 8) | adxl345_read(0x32);

Peter

Thanks!!! I am finally reading values!!! Holy Mackerels, I get huge numbers but they change when I move the adxl345!

Hey! I was just checking out your post and was wondering what you ended up with as the final code @LeonKuro ? I tried updating what you had posted @peter , but I seem to have gotten confused from the ‘spi.writeread’
`#define ADXL345_DEVICE 0x53;

local values = [0,0,0,0,0,0,0,0,0,0];
//pin 1 is CS and should be driven high unless transmitting
hardware.pin1.configure(DIGITAL_OUT);
hardware.pin1.write(1); // nCS high by default

//program start
hardware.spi257.configure(MSB_FIRST|CLOCK_IDLE_HIGH|CLOCK_2ND_EDGE, 500);

function adxl345_write(reg, value) {
// See ADXL345 datasheet figure 37
hardware.pin1.write(0); // set nCS low
// R/nW=0 MB=0 so first byte is just the register number
hardware.spi257.write(reg.tochar() + value.tochar());
hardware.pin1.write(1); // nCS back high again
}
adxl345_write(0x2D, 0x08);
adxl345_write(0x31, 0x01);
adxl345_write(0x38, 0x00);

function adxl345_read(reg) {
hardware.pin1.write(0);
// R/nW=1 MB=0, second byte doesn’t matter
local ret = hardware.spi257.read((reg + 0x80).tochar() + " ")
local x = (adxl345_read(0x33) << 8) | adxl345_read(0x32);
hardware.pin1.write(1);
return ret;
}
local x = adxl345_read(0X32 + 0x33);
local y = adxl345_read(0x34 + 0x35);
local z = adxl345_read(0x36 + 0x37);
//x = (values[1] << 8 | values[0]);
//y = (values[3] << 8 | values[2]);
//z = (values[5] << 8 | values[4]);
server.log(x);
server.log(y);
server.log(z);`

From this but I get Error:bad parameters for spi.read(size) and Error: at adxl345_read:26
and line 26 is " local x = (adxl345_read(0x33) << 8) | adxl345_read(0x32);"

That looks OK up to adxl345_read(); from there-on, try this instead:

`function adxl345_read(reg) {
hardware.pin1.write(0);
// R/nW=1 MB=0, second byte doesn’t matter
local ret = hardware.spi257.writeread((reg + 0x80).tochar() + " ")
hardware.pin1.write(1);
return ret[1];
}

local x = (adxl345_read(0x33) << 8) | adxl345_read(0x32);
local y = (adxl345_read(0x35) << 8) | adxl345_read(0x34);
local z = (adxl345_read(0x37) << 8) | adxl345_read(0x36);
server.log(x);
server.log(y);
server.log(z);`

Or see here: https://gist.github.com/smittytone/988a9aceb652d769a768

Peter

Hey, thanks @Peter. I tried the link you sent, although it seems I only get x, y and x to equal 0 or at some points x, y and z will all be 65535. Not too sure why it isn’t updating?

` // ADXL345 Register Values

const DEVICE_ID = 0x00; // Device ID register
const POWER_CTL = 0x2D; // Power Control register
const DATA_FORMAT = 0x31; // Data storage format register
const DATAX0 = 0x32; //X-Axis Data 0
const DATAX1 = 0x33; //X-Axis Data 1
const DATAY0 = 0x34; //Y-Axis Data 0
const DATAY1 = 0x35; //Y-Axis Data 1
const DATAZ0 = 0x36; //Z-Axis Data 0
const DATAZ1 = 0x37; //Z-Axis Data 1

// Program constants

const HIGH = 1;
const LOW = 0;
const READING_INTERVAL = 1.0;

// Global Variables

// SPI bus and the SS pin

spi <- hardware.spi257;
ss <- hardware.pin8;

// SPI input buffer

data <- blob(6);

// SPI Functions

function spi_write_reg(register, value)
{
// Write the value to the specified register on the SPI bus

// Lower the SS (CS) to signal start of transmission

ss.write(LOW);

// Now send the data. First write the register value to the bus
// by converting it to a blob

local b1 = blob();
b1.writen(register, 'b');
spi.write(b1);

// Now write the value that register will take, again by first
// converting the integer value to a blob

local b2 = blob();
b2.writen(value, 'b');
spi.write(b2);

// Finally, we've done sending, so put SS high again 
// to signal end-of-transaction

ss.write(HIGH);

}

function spi_read_reg(register, num_bytes)
{
// Read the value at the specified register via the SPI bus

local b = blob();
local r = register;

// Lower the SS (CS) to signal start of transmission

ss.write(LOW);

// The ADXL345 requires certain flag bits to be set in the register address
// First, set the 'multi-byte read/write bit' (bit 6) in address, if we are
// reading more than one byte of data

if (num_bytes > 1) r = r | 0x40;

// Second, read operations require address bit 7 to be set

r = r | 0x80;

// Convert address to blob and write it to the bus

b.writen(r, 'b');
spi.write(b);

// Now read in the data

data = spi.readblob(num_bytes);

// Finally, we've done sending, so put SS high again 
// to signal end-of-transaction

ss.write(HIGH);

}

// ADXL345 Functions

function init_adxl345()
{
local x = 0, y = 0, z = 0;

// Send 0x08 to the ADXL345's power register to turn it on
// and apply the level of sensitivity we want

spi_write_reg(POWER_CTL, 0x08);

// As a check, read the value in register 0x00,  the device ID
// This should log 'E5' if the ADXL345 is working

spi_read_reg(DEVICE_ID, 1);
server.log(format("ADXL345 Fixed ID: %X",data[0]));

// Put the ADXL345 into measurement mode, for reading real movement

spi_write_reg(DATA_FORMAT, 0x00);

}

// Program Functions

function loop()
{
// Schedule the next reading

imp.wakeup(READING_INTERVAL, loop);

// Take a reading

spi_read_reg(DATAX0, 6);

// Get X, Y and Z values from SPI reading

local x = (data[1] << 8)|data[0];
local y = (data[3] << 8)|data[2];
local z = (data[5] << 8)|data[4];

// Subtract the values from the saved standard values and display

server.log(format("X: %u, Y: %u, Z:%u", x  , y, z));

}

// START OF PROGRAM

// The ADXL345 uses SPI Mode 3, ie. CPOL 1, CPHA 1
// The imp API docs translate this to (CLOCK_IDLE_HIGH | CLOCK_2ND_EDGE)

spi.configure((CLOCK_IDLE_HIGH | CLOCK_2ND_EDGE), 100);

// Configure the SS pin and set it high

ss.configure(DIGITAL_OUT);
ss.write(HIGH);

// Initialise the accelerometer

init_adxl345();

// Take the first reading

loop(); `

Did you try the gist link? Smittytone’s code was tested with actual hardware.

Turns out my connections were bad! It works perfectly! :smiley: