Hi everyone,
I'm having some troubles in reading the output from a IIS3DWB accelerometer; I tried using an Arduino Uno and a STM32L476RE (with an official arduino core) and got the same result; this is the output from one axis:
the signal randomly drops (or rises) for one sample to a meaningless value.
I'm using this library and adapted it to my needs; the code below is for the STM32 but I used a similar one for the Arduino Uno. I'm using a timer in order to raise a flag and do the reading;
#include "IIS3DWB.h"
#include "SPI.h"
#define CSPIN D2
/* Specify sensor parameters (sample rate is same as the bandwidth 6.3 kHz by default)
choices are: AFS_2G, AFS_4G, AFS_8G, AFS_16G
*/
uint8_t Ascale = AFS_4G;
int16_t IIS3DWBDataZ[1] = {0}; // Stores the 16-bit signed sensor output
int16_t data = 0;
float ax, ay, az, accelTemp; // variables to hold latest accel data values
uint8_t IIS3DWBstatus;
volatile bool timetoread = false;
IIS3DWB IIS3DWB(CSPIN); // instantiate IIS3DWB class
void setup()
{
Serial.begin(2000000);
delay(4000);
SPI.begin(); // Start SPI serial peripheral
SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE3));
// Configure SPI ship select for sensor breakout
pinMode(CSPIN, OUTPUT);
pinMode(CSPIN, HIGH); // disable SPI at start
// Read the IIS3DWB Chip ID register, this is a good test of communication
Serial.println("IIS3DWB accel...");
uint8_t c = IIS3DWB.getChipID(); // Read CHIP_ID register for IIS3DWB
Serial.print("IIS3DWB "); Serial.print("I am "); Serial.print(c, HEX); Serial.print(" I should be "); Serial.println(0x7B, HEX);
Serial.println(" ");
if (c == 0x7B) // check if all SPI sensors have acknowledged
{
Serial.println("IIS3DWB is online...");
Serial.println(" ");
// reset IIS3DWB to start fresh
IIS3DWB.reset();
IIS3DWB.selfTest();
IIS3DWB.init(Ascale); // configure IIS3DWB
IIS3DWB.enableSingleAxisMode('z');
Serial.println("single axis mode activated for z axis");
delay(1000);
}
else
{
if (c != 0x6A) Serial.println(" IIS3DWB not functioning!");
while (1) {};
}
TIM_TypeDef *Instance1 = TIM1;
// Instantiate HardwareTimer object. Thanks to 'new' instanciation, HardwareTimer is not destructed when setup() function is finished.
HardwareTimer *MyTim1 = new HardwareTimer(Instance1);
MyTim1->setOverflow(400, HERTZ_FORMAT);
MyTim1->attachInterrupt(update_callback1);
MyTim1->resume();
}
/* End of setup */
void loop() {
if (timetoread) // Handle data ready condition
{
timetoread = false;
IIS3DWB.readAccelDataAxis(IIS3DWBDataZ, 'z');
Serial.println ( IIS3DWBDataZ[0]);
} // end activity change interrupt handling
}
void update_callback1(void)
{
timetoread = true;
}
and this is the readAccelDataAxis (and readBytes) function I'm using; each axis output is taken from two registers and combined in a 16 bit signed number; no need to call a readbyte also for the second register as the sensor shifts automatically registers in case of a multi-byte transaction:
void IIS3DWB::readAccelDataAxis(int16_t * destination,char axis)
{
uint8_t rawData[2]; // x/y/z accel register data stored here
switch (axis)
{
case 'x':
readBytes(IIS3DWB_OUTX_L_XL, 2, &rawData[0]); // Read the 2 raw accel data registers into data array
break;
case 'y':
readBytes(IIS3DWB_OUTY_L_XL, 2, &rawData[0]); // Read the 2 raw accel data registers into data array
break;
case 'z':
readBytes(IIS3DWB_OUTZ_L_XL, 2, &rawData[0]); // Read the 2 raw accel data registers into data array
break;
}
*destination = (int16_t)((int16_t)rawData[1] << 8) | rawData[0] ;
}
void IIS3DWB::readBytes(uint8_t reg, uint8_t count, uint8_t * dest)
{
digitalWrite(_cs, LOW);
SPI.transfer((reg & 0x7F) | 0x80);
for (uint8_t ii = 0; ii < count; ii++)
dest[ii] = SPI.transfer(0);
digitalWrite(_cs, HIGH);
}
Just to make things clear I attach an image showing a multi-byte transaction fron the accelerometer datasheet;
Experiments that I tried but didn't work: lowering SPI speed transaction (the sensor is rated for up to 10MHz speed), changing SPI mode (the sensor accepts mode 0 and 3), lowering timer frequency, doing the reading in the update_callback1 function (I was thinking that maybe the interrupt was disturbing the SPI transaction somehow).
Do you have any idea of why this is happening?
Thanks in advance

