-
Notifications
You must be signed in to change notification settings - Fork 2
/
lis3dsh.cpp
164 lines (136 loc) · 5.74 KB
/
lis3dsh.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*
* File: lis3dsh.cpp
* Author: Michele Liscio
* Author: Andrea Cirigliano
*
* brief : this class configures the accelerometer for the specified purpose; in the
* case of our project, it's the freefall purpose.
*
* Created on 10 gennaio 2015, 12.14
*/
#include <miosix.h>
#include "spi.h"
#include "lis3dsh_reg.h"
#include "lis3dsh.h"
#include "IRQhandler.h"
using namespace miosix;
/* SPI istance here defined because of integrability (someone interested in the
freefall detection doesn't have to call the spi.config but only the accelerometer.config */
Spi spi;
IRQhandler irqHandler;
/* ============================= LEDS UTILITY =============================== */
typedef Gpio<GPIOD_BASE, 15> blueLed;
typedef Gpio<GPIOD_BASE, 14> redLed;
typedef Gpio<GPIOD_BASE, 13> orangeLed;
typedef Gpio<GPIOD_BASE, 12> greenLed;
void Lis3dsh::blinkLeds() {
blueLed::high(); redLed::high(); orangeLed::high();
usleep(1000000);
blueLed::low(); redLed::low(); orangeLed::low();
}
/* ============================ END LEDS UTILITY =============================*/
/**
* @brief Configures the accelerometer for the free-fall detection.
* @param minDuration : The minimum duration (in milliseconds) of subthreshold accelerations for recognize a free-fall condition.
* Allowed range [2,5 - 637,5]ms.
* @param threshold : The maximum acceleration (in milli-g) that is recognized as free-fall condition.
* The lower is the threshold, more accurate is the recognition.
* Allowed range [15,625 - 3984]mg.
*/
void Lis3dsh::freeFallConfig(float minDuration, float threshold) {
blueLed::mode(Mode::OUTPUT); redLed::mode(Mode::OUTPUT);
orangeLed::mode(Mode::OUTPUT); greenLed::mode(Mode::OUTPUT);
spi.config();
uint8_t timer1 = convertTime(minDuration);
uint8_t threshold2 = convertThreshold(threshold);
uint8_t toSend[2];
toSend[ADDR] = CTRL_REG4;
toSend[DATA] = CTRL_REG4_XEN | CTRL_REG4_YEN | CTRL_REG4_ZEN; //accelerometer axis enabled
toSend[DATA] |= CTRL_REG4_ODR0 | CTRL_REG4_ODR1 | CTRL_REG4_ODR2; //output data rate at 400 Hz
spi.writeAndRead(toSend, WRITE);
toSend[ADDR] = CTRL_REG3;
toSend[DATA] = CTRL_REG3_INT1EN; //interrupt1 enabled, signals when freefall is detected
toSend[DATA] |= CTRL_REG3_IEA; //interrupt signal active high
spi.writeAndRead(toSend, WRITE);
toSend[ADDR] = TIM1_1L; //timer 1 for State Machine 1
toSend[DATA] = timer1; //free fall duration
spi.writeAndRead(toSend, WRITE);
toSend[ADDR] = THRS2_1; // threshold 2 for State Machine 1
toSend[DATA] = threshold2; //free-fall threshold
spi.writeAndRead(toSend, WRITE);
toSend[ADDR] = MASK1_B;
toSend[DATA] = MASK1_B_P_X | MASK1_B_P_Y | MASK1_B_P_Z; //enable positive X, Y and Z in mask B
spi.writeAndRead(toSend, WRITE);
toSend[ADDR] = MASK1_A;
toSend[DATA] = MASK1_A_P_X | MASK1_A_P_Y | MASK1_A_P_Z; //enable positive X, Y and Z in mask A
spi.writeAndRead(toSend, WRITE);
toSend[ADDR] = SETT1;
toSend[DATA] = SETT1_SITR; //STOP and CONT commands generate an interrupt and perform output actions as OUTC command
toSend[DATA] |= SETT1_R_TAM; //NEXT condition validation : standard mask always evaluated
spi.writeAndRead(toSend, WRITE);
/* ========================== STATE MACHINE CONFIG =======================*/
toSend[ADDR] = ST1_1; //state machine 1, state 1
/* set NOP (no-operation) in the RESET condition;
* also set the NEXT condition (how to go in the next state) : if LLTH2 (the acc
* of axis are less than or equal to threshold 2) */
toSend[DATA] = (NOP RESET) | (LLTH2 NEXT);
spi.writeAndRead(toSend, WRITE);
toSend[ADDR] = ST1_2; //state machine 1, state 2
/* set the RESET condition : if GNTH2 (the acc of axis become greater than threshold 2) ;
* also set the NEXT condition : TI1 (check if 100 ms passed) */
toSend[DATA] = (GNTH2 RESET) | (TI1 NEXT);
spi.writeAndRead(toSend, WRITE);
toSend[ADDR] = ST1_3; //state machine 1, state 3
toSend[DATA] = CONT; //set CONT (the final state where the freefall condition is verified)
spi.writeAndRead(toSend, WRITE);
toSend[ADDR] = CTRL_REG1;
toSend[DATA] = CTRL_REG1_SM1_EN; //enabled State Machine 1
spi.writeAndRead(toSend, WRITE);
/*====================== END OF STATE MACHINE CONFIG =====================*/
irqHandler.configureAccInterrupt(); //configure interrupt 1 handler
}
/**
* @brief the main accelerometer function that loops and detects the free fall
*/
void Lis3dsh::freeFallDetectionInit() {
uint8_t toReceive[2];
for (;;)
{
irqHandler.waitForInt1();
blinkLeds();
toReceive[ADDR] = OUTS1; // OUTS1 register: reading this, the interrupt signal is reset
spi.writeAndRead(toReceive, READ);
}
}
/**
* @brief converts time from milliseconds to the corresponding byte
* @param milliseconds : the freefall detection time interval expressed in milliseconds
* @return byte : the time interval converted in byte
*/
uint8_t Lis3dsh::convertTime(float milliseconds){
// 1 LSB = 1/ODR = 1/400 Hz
float temp = milliseconds / (2.5);
int byte = (int) temp;
if (byte < 0)
return 0;
else if (byte > 255)
return 255;
else
return (uint8_t) byte;
}
/**
* @brief converts acceleration from milli-g to the corresponding byte
* @param milliG : the threshold expressed in milliG
* @return byte : the threshold converted in byte
*/
uint8_t Lis3dsh::convertThreshold(float milliG) {
// 1 LSB = 2g/(2^7)
float temp = milliG / (15.625);
int byte = (int) temp;
if (byte < 0)
return 0;
else if (byte > 255)
return 255;
else
return (uint8_t) byte;
}