Statistics
| Branch: | Tag: | Revision:

amiro-os / components / accel / lis331dlh.cpp @ 8dbafe16

History | View | Annotate | Download (11.265 KB)

1
#include <string.h>
2

    
3
#include <amiro/util/util.h>
4
#include <amiro/bus/spi/HWSPIDriver.hpp>
5
#include <amiro/accel/lis331dlh.hpp>
6
#include <chprintf.h>
7
#include <cmath>  // abs()
8
#include <amiro/Constants.h>
9

    
10
namespace amiro {
11

    
12
LIS331DLH::
13
LIS331DLH(HWSPIDriver *driver) :
14
  driver(driver),
15
  currentFullScaleConfiguration(FS_2G) {
16

    
17
}
18

    
19
LIS331DLH::
20
~LIS331DLH() {
21

    
22
}
23

    
24
chibios_rt::EvtSource*
25
LIS331DLH::
26
getEventSource() {
27
  return &this->eventSource;
28
}
29

    
30
int16_t
31
LIS331DLH::
32
getAcceleration(const uint8_t axis) {
33

    
34
  return this->accelerations[axis];
35

    
36
}
37

    
38
int16_t
39
LIS331DLH::
40
getAccelerationForce(const uint8_t axis) {
41

    
42
  int16_t result;
43

    
44
  switch(this->currentFullScaleConfiguration) {
45
  default:
46
  case(FS_2G):
47
    // Should be this->accelerations[axis] * 0.9765625
48
    result = this->accelerations[axis];
49
    break;
50
  case(FS_4G):
51
      // Should be this->accelerations[axis] * 1.953125
52
      result =  this->accelerations[axis] << 1;
53
    break;
54
  case(FS_8G):
55
      // Should be this->accelerations[axis] * 3.90625
56
      result =  this->accelerations[axis] << 2;
57
    break;
58
  }
59

    
60
  return result;
61

    
62
}
63

    
64
msg_t
65
LIS331DLH::
66
main() {
67

    
68
  this->setName("Lis331dlh");
69

    
70
  while (!this->shouldTerminate()) {
71

    
72
    updateSensorData();
73

    
74
    this->eventSource.broadcastFlags(0);
75

    
76
    this->waitAnyEventTimeout(ALL_EVENTS, CAN::UPDATE_PERIOD);
77

    
78
  }
79
  return RDY_OK;
80
}
81

    
82
void
83
LIS331DLH::
84
updateSensorData() {
85

    
86
  const size_t buffer_size = offsetof(LIS331DLH::registers, out_z)
87
                             - offsetof(LIS331DLH::registers, status_reg)
88
                             + MEMBER_SIZE(LIS331DLH::registers, out_z)
89
                             + 1; /* addressing */
90
  uint8_t buffer[buffer_size];
91
  uint8_t sreg;
92

    
93
  // this might be three-wire so we need to send ones
94
  memset(buffer, 0xFFu, buffer_size);
95
  buffer[0] = offsetof(LIS331DLH::registers, status_reg) | LIS331DLH::SPI_MULT | LIS331DLH::SPI_READ;
96
  this->driver->exchange(buffer, buffer, buffer_size);
97

    
98
  // assemble data
99
  sreg = buffer[1];
100

    
101
  if (sreg & LIS331DLH::XDA)
102
    this->accelerations[LIS331DLH::AXIS_X] = int16_t((buffer[3] << 8) | buffer[2]) >> 4;
103

    
104
  if (sreg & LIS331DLH::YDA)
105
    this->accelerations[LIS331DLH::AXIS_Y] = int16_t((buffer[5] << 8) | buffer[4]) >> 4;
106

    
107
  if (sreg & LIS331DLH::ZDA)
108
    this->accelerations[LIS331DLH::AXIS_Z] = int16_t((buffer[7] << 8) | buffer[6]) >> 4;
109

    
110
}
111

    
112
msg_t
113
LIS331DLH::
114
configure(LIS331DLHConfig *config) {
115

    
116
  const size_t ctrl_reg_size = offsetof(LIS331DLH::registers, ctrl_reg5)
117
                               - offsetof(LIS331DLH::registers, ctrl_reg1)
118
                               + MEMBER_SIZE(LIS331DLH::registers, ctrl_reg5)
119
                               + 1; /* addressing */
120
  const size_t int_reg_size = offsetof(LIS331DLH::registers, int1_duration)
121
                              - offsetof(LIS331DLH::registers, int1_cfg)
122
                              + MEMBER_SIZE(LIS331DLH::registers, int1_duration) /* linear interrupt config */
123
                              + MEMBER_SIZE(LIS331DLH::registers, int1_src)
124
                              + MEMBER_SIZE(LIS331DLH::registers, int1_src) /* 2x size of int1_src */
125
                              + 1; /* addressing */
126
  const size_t buffer_size = ctrl_reg_size > int_reg_size ? ctrl_reg_size : int_reg_size;
127

    
128
  uint8_t buffer[buffer_size];
129
  InterruptConfig *int_cfg = &config->int1_cfg;
130
  uint8_t i;
131

    
132
  // write interrupt config first
133
  for (i = 0x00u; i < 2; i++, int_cfg++) {
134
    // this might be three-wire so we need to send ones
135
    memset(buffer, 0xFFu, buffer_size);
136
    if (!i)
137
      buffer[0] = offsetof(LIS331DLH::registers, int1_cfg);
138
    else
139
      buffer[0] = offsetof(LIS331DLH::registers, int2_cfg);
140
    buffer[5] = buffer[0] + offsetof(LIS331DLH::registers, int1_src) - offsetof(LIS331DLH::registers, int1_cfg);
141
    buffer[5] |= LIS331DLH::SPI_READ;
142
    buffer[6] = 0xFFu,
143
    buffer[0] |= LIS331DLH::SPI_MULT | LIS331DLH::SPI_WRITE;
144
    buffer[1] = int_cfg->config;
145
    buffer[2] = 0xFFu; /* skip source register */
146
    buffer[3] = int_cfg->ths;
147
    buffer[4] = int_cfg->duration;
148
    this->driver->write(&buffer[0], 5);
149
    // read intN_src register to clear IA
150
    this->driver->exchange(&buffer[5], &buffer[5], 2);
151
  }
152

    
153
  // write control config
154
  // this might be three-wire so we need to send ones
155
  memset(buffer, 0xFFu, buffer_size);
156
  buffer[0] = offsetof(LIS331DLH::registers, ctrl_reg1) | LIS331DLH::SPI_MULT | LIS331DLH::SPI_WRITE;
157
  buffer[1] = config->ctrl1;
158
  buffer[2] = config->ctrl2;
159
  buffer[3] = config->ctrl3;
160
  buffer[4] = config->ctrl4;
161
  buffer[5] = config->ctrl5;
162
  this->driver->write(buffer, 6);
163

    
164
  // reset hp filter
165
  buffer[0] = offsetof(LIS331DLH::registers, hp_filter_reset) | LIS331DLH::SPI_WRITE;
166
  this->driver->write(buffer, 1);
167

    
168
  // Store the full scale configuration for acceleration decoding
169
  this->currentFullScaleConfiguration = config->ctrl4 & LIS331DLH::FS_8G;
170

    
171
  return RDY_OK;
172

    
173
}
174

    
175
uint8_t
176
LIS331DLH::
177
getCheck() {
178

    
179
  const size_t buffer_size = 1 /* addressing */
180
                             + 1; /* who am i */
181
  uint8_t buffer[buffer_size];
182

    
183
  // Exchange the data with the LIS331DLH accelerometer
184
  // Specify the adress and the mode
185
  buffer[0] = offsetof(LIS331DLH::registers, who_am_i) | LIS331DLH::SPI_READ;
186
  this->driver->exchange(buffer, buffer, buffer_size);
187
  // Check
188
  if (buffer[1] == LIS331DLH::LIS331DLH_ID) {
189
    return LIS331DLH::CHECK_OK;
190
  } else {
191
    return LIS331DLH::CHECK_FAIL;
192
  }
193

    
194
}
195

    
196
void
197
LIS331DLH::
198
printSelfTest(LIS331DLHConfig* config) {
199

    
200
  // Running the build in test from LIS331DLH manual and compare the
201
  // measured values against table 3
202

    
203
  const uint8_t amountOfMeanValues = 10;
204
  const uint32_t sleepBetweenMeasurementMs = 500;
205
  int32_t accel;
206

    
207
  // Choose a defined config, if none is given
208
  LIS331DLH::LIS331DLHConfig test_accel_run_cfg;
209
  if (config == NULL) {
210
    LIS331DLH::LIS331DLHConfig accel_run_cfg_tmp = {
211
    /* ctrl1    */LIS331DLH::PM_ODR | LIS331DLH::DR_50HZ_37LP | LIS331DLH::ZEN
212
        | LIS331DLH::YEN | LIS331DLH::XEN,
213
    /* ctrl2    */0x00u,
214
    /* ctrl3    */LIS331DLH::INT_LOW | LIS331DLH::I1_CFG_DRY,
215
    /* ctrl4    */LIS331DLH::BDU_CONT | LIS331DLH::BLE_LE | LIS331DLH::FS_8G
216
        | LIS331DLH::SIM_4WI,
217
    /* ctrl5    */LIS331DLH::SLEEP_TO_WAKE_OFF,
218
    /* int1_cfg */
219
    {
220
    /* config   */LIS331DLH::AOI_OR_INT,
221
    /* ths      */0x00u,
222
    /* duration */0x00u, },
223
    /* int2_cfg */
224
    {
225
    /* config   */LIS331DLH::AOI_OR_INT,
226
    /* ths      */0x00u,
227
    /* duration */0x00u, }, };
228
    test_accel_run_cfg = accel_run_cfg_tmp;
229
  } else {
230
    // Save the given config
231
    test_accel_run_cfg = *config;
232
  }
233

    
234
  // 1. Get some standard values
235
  // Configure for the test
236
  test_accel_run_cfg.ctrl4 = LIS331DLH::BDU_CONT | LIS331DLH::BLE_LE
237
      | LIS331DLH::FS_2G | LIS331DLH::SIM_4WI;
238
  this->configure(&test_accel_run_cfg);
239
  BaseThread::sleep(MS2ST(sleepBetweenMeasurementMs));
240
  // Grep some values and build the mean value
241
  chprintf((BaseSequentialStream*) &SD1, "\nACC: Get acc std values\n");
242
  int32_t stdAccValues[3] = { this->getAcceleration(LIS331DLH::AXIS_X), this
243
      ->getAcceleration(LIS331DLH::AXIS_Y), this->getAcceleration(
244
      LIS331DLH::AXIS_Z) };
245

    
246
  for (uint8_t n = 1; n < amountOfMeanValues; ++n) {
247
    BaseThread::sleep(MS2ST(sleepBetweenMeasurementMs));
248
    for (uint8_t i = LIS331DLH::AXIS_X; i <= LIS331DLH::AXIS_Z; i++) {
249
      accel = int32_t(this->getAcceleration(i));
250
      stdAccValues[i] = (stdAccValues[i] * n + accel) / (n + 1);
251
      chprintf((BaseSequentialStream*) &SD1, "%c%d:%d ", accel < 0 ? '-' : '+',
252
                accel < 0 ? -accel : accel, stdAccValues[i]);
253
    }
254
    chprintf((BaseSequentialStream*) &SD1, "\n");
255
  }
256

    
257
  // 2. Apply negative offset
258
  // Configure for the test
259
  test_accel_run_cfg.ctrl4 = LIS331DLH::BDU_CONT | LIS331DLH::BLE_LE
260
      | LIS331DLH::FS_2G | LIS331DLH::SIM_4WI | LIS331DLH::ST_ENABLE
261
      | LIS331DLH::STSIGN_NEG;
262
  this->configure(&test_accel_run_cfg);
263
  BaseThread::sleep(MS2ST(sleepBetweenMeasurementMs));
264
  // Grep some values and build the mean value
265
  chprintf((BaseSequentialStream*) &SD1, "\nACC: Get acc neg values\n");
266
  int16_t negAccValues[3] = { this->getAcceleration(LIS331DLH::AXIS_X), this
267
      ->getAcceleration(LIS331DLH::AXIS_Y), this->getAcceleration(
268
      LIS331DLH::AXIS_Z) };
269

    
270
  for (uint8_t n = 1; n < amountOfMeanValues; ++n) {
271
    BaseThread::sleep(MS2ST(sleepBetweenMeasurementMs));
272
    for (uint8_t i = LIS331DLH::AXIS_X; i <= LIS331DLH::AXIS_Z; i++) {
273
      accel = int32_t(this->getAcceleration(i));
274
      negAccValues[i] = (negAccValues[i] * n + accel) / (n + 1);
275
      chprintf((BaseSequentialStream*) &SD1, "%c%d:%d ", accel < 0 ? '-' : '+',
276
                accel < 0 ? -accel : accel, negAccValues[i]);
277
    }
278
    chprintf((BaseSequentialStream*) &SD1, "\n");
279
  }
280

    
281
  // 2. Apply positive offset
282
  // Configure for the test
283
  test_accel_run_cfg.ctrl4 = LIS331DLH::BDU_CONT | LIS331DLH::BLE_LE
284
      | LIS331DLH::FS_2G | LIS331DLH::SIM_4WI | LIS331DLH::ST_ENABLE
285
      | LIS331DLH::STSIGN_POS;
286
  this->configure(&test_accel_run_cfg);
287
  BaseThread::sleep(MS2ST(sleepBetweenMeasurementMs));
288
  // Grep some values and build the mean value
289
  chprintf((BaseSequentialStream*) &SD1, "\nACC: Get acc pos values\n");
290
  int16_t posAccValues[3] = { this->getAcceleration(LIS331DLH::AXIS_X), this
291
      ->getAcceleration(LIS331DLH::AXIS_Y), this->getAcceleration(
292
      LIS331DLH::AXIS_Z) };
293

    
294
  for (uint8_t n = 1; n < amountOfMeanValues; ++n) {
295
    BaseThread::sleep(MS2ST(sleepBetweenMeasurementMs));
296
    for (uint8_t i = LIS331DLH::AXIS_X; i <= LIS331DLH::AXIS_Z; i++) {
297
      accel = int32_t(this->getAcceleration(i));
298
      posAccValues[i] = (posAccValues[i] * n + accel) / (n + 1);
299
      chprintf((BaseSequentialStream*) &SD1, "%c%d:%d ", accel < 0 ? '-' : '+',
300
                accel < 0 ? -accel : accel, posAccValues[i]);
301
    }
302
    chprintf((BaseSequentialStream*) &SD1, "\n");
303
  }
304

    
305
  // Get the amplitude change and compare it to the standard values from LIS331DLH manual table 3
306
  int32_t amp;
307
  const int32_t ampXmax = 550, ampYmax = 550, ampZmax = 750;
308
  const int32_t ampXmin = 120, ampYmin = 120, ampZmin = 140;
309

    
310
  // TEST
311
  chprintf((BaseSequentialStream*) &SD1, "\n\nACC: Testresult\n");
312
  amp = std::abs(
313
      stdAccValues[LIS331DLH::AXIS_X] - negAccValues[LIS331DLH::AXIS_X]);
314
  if (amp < ampXmin || amp > ampXmax)
315
    chprintf((BaseSequentialStream*) &SD1, "ACC: Negative x-axis faulty\n");
316
  amp = std::abs(
317
      stdAccValues[LIS331DLH::AXIS_Y] - negAccValues[LIS331DLH::AXIS_Y]);
318
  if (amp < ampYmin || amp > ampYmax)
319
    chprintf((BaseSequentialStream*) &SD1, "ACC: Negative y-axis faulty\n");
320
  amp = std::abs(
321
      stdAccValues[LIS331DLH::AXIS_Z] - negAccValues[LIS331DLH::AXIS_Z]);
322
  if (amp < ampZmin || amp > ampZmax)
323
    chprintf((BaseSequentialStream*) &SD1, "ACC: Negative z-axis faulty\n");
324
  amp = std::abs(
325
      stdAccValues[LIS331DLH::AXIS_X] - posAccValues[LIS331DLH::AXIS_X]);
326
  if (amp < ampXmin || amp > ampXmax)
327
    chprintf((BaseSequentialStream*) &SD1, "ACC: Positive x-axis faulty\n");
328
  amp = std::abs(
329
      stdAccValues[LIS331DLH::AXIS_Y] - posAccValues[LIS331DLH::AXIS_Y]);
330
  if (amp < ampYmin || amp > ampYmax)
331
    chprintf((BaseSequentialStream*) &SD1, "ACC: Positive y-axis faulty\n");
332
  amp = std::abs(
333
      stdAccValues[LIS331DLH::AXIS_Z] - posAccValues[LIS331DLH::AXIS_Z]);
334
  if (amp < ampZmin || amp > ampZmax)
335
    chprintf((BaseSequentialStream*) &SD1, "ACC: Positive z-axis faulty\n");
336

    
337
  // Write back the original config
338
  this->configure(config);
339
}
340

    
341
} /* amiro */