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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#![no_std]
use dev_csr::dev_csr;
use embedded_hal::spi::ErrorType;
use embedded_hal_async::spi::SpiBus;
use spi_handle::SpiHandle;
use core::mem;
dev_csr!{
dev H3lis {
regs {
/// Should be 32h
0x0F WHO_AM_I r who_am_i,
0x20 CTRL_REG1 rw {
/// 0 disabled, 1 enabled
0 x_enable,
/// 0 disabled, 1 enabled
1 y_enable,
/// 0 disabled, 1 enabled
2 z_enable,
/// 00: 50Hz Output Data Rate, 37Hz Low Pass filter cutoff
/// 01 100Hz Output Data Rate, 74Hz Low Pass filter cutoff
/// 10 400Hz Output Data Rate, 292Hz Low Pass filter cutoff
3..4 data_rate,
/// 000: Power-down
/// 001: Normal mode, uses selected data rate from data_rate
/// 010: Low Power, 0.5Hz Output data rate
/// 011: Low Power, 1Hz Output data rate
/// 100: Low Power, 2Hz Output data rate
/// 101: Low Power, 5Hz Output data rate
/// 110: Low Power, 10Hz Output data rate
5..7 power_mode
},
0x21 CTRL_REG2 rw {
0..1 high_pass_filter_cutoff_freq,
2 high_pass_filter_enabled_interrupt_1,
3 high_pass_filter_enabled_interrupt_2,
/// Filtered data selection. Default value: 0
/// (0: internal filter bypassed; 1: data from internal filter sent to output register)
4 filtered_data_selection,
/// 0 = normal mode
5..6 high_pass_filter_mode,
/// Reboots memory content when true
7 boot
},
0x22 CTRL_REG3 rw{
/// Defualt value: 00
/// 00: Interrupt 1 (2) source
/// 01: Interrupt 1 source OR interrupt 2 source
/// 10: Data ready
/// 11: Boot running
0..1 data_signal_on_int1_pad,
/// (0: interrupt request not latched; 1: interrupt request latched)
2 latch_interrupt_request_int1_src,
/// Default value: 00
3..4 data_signal_on_int2_pad_control_bits,
/// (0: interrupt request not latched; 1: interrupt request latched)
5 latch_interrupt_request_int2_src,
/// (0: push-pull; 1: open-drain)
6 push_pull_open_drain,
/// (0: active high; 1: active low)
7 interrupt_active
},
0x23 CTRL_REG4 rw{
/// Default value: 0
/// (0: 4-wire interface; 1: 3-wire interface)
0 spi_serial_interface_mode_selection
},
0x24 CTRL_REG5 rw{
/// Default value: 00
/// (00: sleep-to-wake function is disabled; 11: Device is in low_power mode)
0..1 turn_on_mode_selection
},
/// Reading at this address zeroes instantaneously the content of the internal high-pass filter.
/// If the high-pass filter is enabled, all three axes are instantaneously set to 0 g.
/// This allows the settling time of the high-pass filter to be overcome.
0x25 HP_FILTER_RESET r hp_filter_reset,
0x26 REFERENCE rw {
/// Default value: 00000000
/// Reference value for high pass filter
0..7 reference
},
0x27 STATUS_REG r {
/// Default value: 0
/// (0: no new data ready; 1: new data available)
0 x_data_available,
1 y_data_available,
2 z_data_available,
/// (0: new set of data not available; 1: a new set is available)
3 xyz_data_available,
/// (0: no overrun has occurred; 1: a new data for the same axis has overwritten the previous data)
4 x_overrun,
5 y_overrun,
6 z_overrun,
/// (0: no overrun has occurred; 1: new data has overwritten the previous data before it was read)
7 xyz_overrun
},
0x29 OUT_X r x[0..7],
0x2B OUT_Y r y [0..7],
0x2D OUT_Z r z[0..7],
0x30 INT1_CFG rw {
/// Default value: 0
/// (0: disable interrupt request; 1: enable interrupt request on measured accel. value lower/higher than preset threshold)
0 enable_interrupt_generation_x_low_event_int1,
1 enable_interrupt_generation_x_high_event_int1,
2 enable_interrupt_generation_y_low_event_int1,
3 enable_interrupt_generation_y_high_event_int1,
4 enable_interrupt_generation_z_low_event_int1,
5 enable_interrupt_generation_z_high_event_int1,
/// (0: OR combination of interrupt events; 1: AND combination of interrupt events)
7 and_or_combinayion_of_interrupt_events_int1
},
0x31 INT1_SRC r {
/// Default value: 0
/// (0: no interrupt; 1: event has occurred)
0 x_low_event_int1,
1 x_high_event_int1,
2 y_low_event_int1,
3 y_high_event_int1,
4 z_low_event_int1,
5 z_high_event_int1,
/// (0: no interrupt event has been generated; 1: one or more interrupt events have been generated)
6 interrupt_active_int1
},
0x32 INT1_THS rw {
/// Default value: 000 0000
0..6 interrupt_1_threshold
},
0x33 INT1_DURATION rw {
/// Default value: 000 0000
/// These bits set the minimum duration of the interrupt event to be recognized.
0..6 interrupt_1_duration
},
0x34 INT2_CFG rw {
/// Default value: 0
/// (0: disable interrupt request; 1: enable interrupt request on measured accel. value lower/higher than preset threshold)
0 enable_interrupt_generation_x_low_event_int2,
1 enable_interrupt_generation_x_high_event_int2,
2 enable_interrupt_generation_y_low_event_int2,
3 enable_interrupt_generation_y_high_event_int2,
4 enable_interrupt_generation_z_low_event_int2,
5 enable_interrupt_generation_z_high_event_int2,
/// (0: OR combination of interrupt events; 1: AND combination of interrupt events)
7 and_or_combinayion_of_interrupt_events_int2
},
0x35 INT2_SRC rw {
/// Default value: 0
/// (0: no interrupt; 1: event has occurred)
0 x_low_event_int2,
1 x_high_event_int2,
2 y_low_event_int2,
3 y_high_event_int2,
4 z_low_event_int2,
5 z_high_event_int2,
/// (0: no interrupt event has been generated; 1: one or more interrupt events have been generated)
6 interrupt_active_int2
},
0x36 INT2_THS rw {
/// Default value: 000 0000
0..6 interrupt_2_threshold
},
0x37 INT2_DURATION rw {
/// Default value: 000 0000
/// These bits set the minimum duration of the interrupt event to be recognized.
0..6 interrupt_2_duration
}
}
}
}
pub struct H3lis<S: SpiHandle> {
spi: S
}
impl <S: SpiHandle> H3lis<S> {
pub fn new(spi: S) -> Self {
Self {
spi
}
}
pub async fn setup(
&mut self
) -> Result<(),<S::Bus as ErrorType>::Error> {
// self.write_reg(reg, value as u8).await?;
// enable x,y,z axis
self.write_reg(RegCtrlReg1, 0b001_10_111 as u8).await?;
//self.write_reg().await?;
Ok(())
}
pub async fn acceleration(&mut self) -> Result<(i32, i32, i32), <S::Bus as ErrorType>::Error> {
Ok(unsafe {
let accel_x: i8 = mem::transmute(self.x().await?);
let accel_y: i8 = mem::transmute(self.y().await?);
let accel_z: i8 = mem::transmute(self.z().await?);
//xyz are corrected so that
//x -> cable direction
//yz follow from right hand rule, x as index finger
((accel_x as i32) * 780000, (accel_y as i32) * -780000, (accel_z as i32) * -780000)
})
}
pub async fn manufacturer_id(&mut self) -> Result<u8, <S::Bus as ErrorType>::Error> {
Ok(self.who_am_i().await?)
}
}
impl <S: SpiHandle> ReadH3lis for H3lis<S>{
type Error = <S::Bus as ErrorType>::Error;
async fn read_contiguous_regs(
&mut self,
addr: impl ReadableAddr,
out: &mut [u8]
) -> Result<(), Self::Error> {
let mut bus = self.spi.select().await;
// bit 0: READ bit. The value is 1.
// bit 1: MS bit. When 0, does not increment the address. When 1, increments the address in multiple reads.
// bit 2-7: address AD(5:0). This is the address field of the indexed register.
// bit 8-15: data DO(7:0) (read mode). This is the data that is read from the device (MSB first).
// bit 16-... : data DO(...-8). Further data in multiple byte reads.
// set rw bit
// write = 1, read = 0
// If broken try | 0b1100_0000;
let addr: u8 = addr.as_addr() | 0b1000_0000;
bus.write(&[addr]).await?;
bus.transfer_in_place(out).await?;
Ok(())
}
}
impl <S: SpiHandle> WriteH3lis for H3lis<S>{
type Error = <S::Bus as ErrorType>::Error;
async fn write_contiguous_regs(
&mut self,
addr: impl WritableAddr,
values: &[u8]
) -> Result<(), Self::Error> {
let mut bus = self.spi.select().await;
// If broken try & 0b0011_1111;
let addr: u8 = addr.as_addr() & 0b0111_1111;
bus.write(&[addr.as_addr()]).await?;
bus.write(values).await?;
Ok(())
}
}