Firmware SDK
twr_lis2dh12.c
1 #include <twr_lis2dh12.h>
2 #include <twr_scheduler.h>
3 #include <twr_exti.h>
4 #include <stm32l0xx.h>
5 
6 #define _TWR_LIS2DH12_DELAY_RUN 10
7 #define _TWR_LIS2DH12_DELAY_READ 10
8 #define _TWR_LIS2DH12_AUTOINCREMENT_ADR 0x80
9 
10 static void _twr_lis2dh12_task_interval(void *param);
11 static void _twr_lis2dh12_task_measure(void *param);
12 static bool _twr_lis2dh12_power_down(twr_lis2dh12_t *self);
13 static bool _twr_lis2dh12_continuous_conversion(twr_lis2dh12_t *self);
14 static bool _twr_lis2dh12_read_result(twr_lis2dh12_t *self);
15 static void _twr_lis2dh12_interrupt(twr_exti_line_t line, void *param);
16 
17 static const float _twr_lis2dh12_fs_lut[] =
18 {
19  [TWR_LIS2DH12_SCALE_2G] = (1/1000.f),
20  [TWR_LIS2DH12_SCALE_4G] = (2/1000.f),
21  [TWR_LIS2DH12_SCALE_8G] = (4/1000.f),
22  [TWR_LIS2DH12_SCALE_16G] = (12/1000.f)
23 };
24 
25 static const float _twr_lis2dh12_ths_lut[] =
26 {
27  [TWR_LIS2DH12_SCALE_2G] = (0.016f),
28  [TWR_LIS2DH12_SCALE_4G] = (0.032f),
29  [TWR_LIS2DH12_SCALE_8G] = (0.062f),
30  [TWR_LIS2DH12_SCALE_16G] = (0.186f)
31 };
32 
33 bool twr_lis2dh12_init(twr_lis2dh12_t *self, twr_i2c_channel_t i2c_channel, uint8_t i2c_address)
34 {
35  memset(self, 0, sizeof(*self));
36 
37  self->_i2c_channel = i2c_channel;
38  self->_i2c_address = i2c_address;
39 
40  twr_i2c_init(self->_i2c_channel, TWR_I2C_SPEED_400_KHZ);
41 
42  // Enable GPIOB clock
43  RCC->IOPENR |= RCC_IOPENR_GPIOBEN;
44 
45  // Errata workaround
46  RCC->IOPENR;
47 
48  // Set input mode
49  GPIOB->MODER &= ~GPIO_MODER_MODE6_Msk;
50 
51  self->_task_id_interval = twr_scheduler_register(_twr_lis2dh12_task_interval, self, TWR_TICK_INFINITY);
52  self->_task_id_measure = twr_scheduler_register(_twr_lis2dh12_task_measure, self, _TWR_LIS2DH12_DELAY_RUN);
53 
54  return true;
55 }
56 
57 void twr_lis2dh12_set_event_handler(twr_lis2dh12_t *self, void (*event_handler)(twr_lis2dh12_t *, twr_lis2dh12_event_t, void *), void *event_param)
58 {
59  self->_event_handler = event_handler;
60  self->_event_param = event_param;
61 }
62 
64 {
65  self->_update_interval = interval;
66 
67  if (self->_update_interval == TWR_TICK_INFINITY)
68  {
69  twr_scheduler_plan_absolute(self->_task_id_interval, TWR_TICK_INFINITY);
70  }
71  else
72  {
73  twr_scheduler_plan_relative(self->_task_id_interval, self->_update_interval);
74 
76  }
77 }
78 
80 {
81  if (self->_measurement_active)
82  {
83  return false;
84  }
85 
86  self->_measurement_active = true;
87 
88  twr_scheduler_plan_now(self->_task_id_measure);
89 
90  return true;
91 }
92 
94 {
95  *result_raw = self->_raw;
96 
97  return self->_accelerometer_valid;
98 }
99 
101 {
102  twr_lis2dh12_result_raw_t result_raw;
103 
104  if (!twr_lis2dh12_get_result_raw(self, &result_raw))
105  {
106  return false;
107  }
108 
109  float sensitivity = _twr_lis2dh12_fs_lut[self->_scale];
110 
111  result_g->x_axis = (result_raw.x_axis >> 4) * sensitivity;
112  result_g->y_axis = (result_raw.y_axis >> 4) * sensitivity;
113  result_g->z_axis = (result_raw.z_axis >> 4) * sensitivity;
114 
115  return true;
116 }
117 
118 static void _twr_lis2dh12_task_interval(void *param)
119 {
120  twr_lis2dh12_t *self = param;
121 
122  twr_lis2dh12_measure(self);
123 
124  twr_scheduler_plan_current_relative(self->_update_interval);
125 }
126 
127 static void _twr_lis2dh12_task_measure(void *param)
128 {
129  twr_lis2dh12_t *self = param;
130 
131  while (true)
132  {
133  switch (self->_state)
134  {
135  case TWR_LIS2DH12_STATE_ERROR:
136  {
137  self->_accelerometer_valid = false;
138 
139  self->_measurement_active = false;
140 
141  if (self->_event_handler != NULL)
142  {
143  self->_event_handler(self, TWR_LIS2DH12_EVENT_ERROR, self->_event_param);
144  }
145 
146  self->_state = TWR_LIS2DH12_STATE_INITIALIZE;
147 
148  return;
149  }
150  case TWR_LIS2DH12_STATE_INITIALIZE:
151  {
152  self->_state = TWR_LIS2DH12_STATE_ERROR;
153 
154  // Read and check WHO_AM_I register
155  uint8_t who_am_i;
156  if (!twr_i2c_memory_read_8b(self->_i2c_channel, self->_i2c_address, 0x0f, &who_am_i))
157  {
158  continue;
159  }
160 
161  if (who_am_i != 0x33)
162  {
163  continue;
164  }
165 
166  uint8_t cfg_reg4 = 0x80 | ((uint8_t) self->_scale << 4) | (((uint8_t) self->_resolution & 0x01) << 3);
167 
168  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, 0x23, cfg_reg4))
169  {
170  continue;
171  }
172 
173  if (!_twr_lis2dh12_power_down(self))
174  {
175  continue;
176  }
177 
178  self->_state = TWR_LIS2DH12_STATE_MEASURE;
179 
180  if (self->_measurement_active)
181  {
183  }
184 
185  return;
186  }
187  case TWR_LIS2DH12_STATE_MEASURE:
188  {
189  self->_state = TWR_LIS2DH12_STATE_ERROR;
190 
191  if (!_twr_lis2dh12_continuous_conversion(self))
192  {
193  continue;
194  }
195 
196  self->_state = TWR_LIS2DH12_STATE_READ;
197 
198  twr_scheduler_plan_current_from_now(_TWR_LIS2DH12_DELAY_READ);
199 
200  return;
201  }
202  case TWR_LIS2DH12_STATE_READ:
203  {
204  self->_state = TWR_LIS2DH12_STATE_ERROR;
205 
206  if (!_twr_lis2dh12_read_result(self))
207  {
208  continue;
209  }
210 
211  // Power down only when no alarm is set
212  if(!self->_alarm_active)
213  {
214  if (!_twr_lis2dh12_power_down(self))
215  {
216  continue;
217  }
218  }
219 
220  self->_accelerometer_valid = true;
221 
222  self->_state = TWR_LIS2DH12_STATE_UPDATE;
223 
224  continue;
225  }
226  case TWR_LIS2DH12_STATE_UPDATE:
227  {
228  self->_state = TWR_LIS2DH12_STATE_ERROR;
229 
230  self->_measurement_active = false;
231 
232  if (self->_event_handler != NULL)
233  {
234  self->_event_handler(self, TWR_LIS2DH12_EVENT_UPDATE, self->_event_param);
235  }
236 
237  // When the interrupt alarm is active
238  if(self->_alarm_active)
239  {
240  uint8_t int1_src;
241 
242  if(!twr_i2c_memory_read_8b(self->_i2c_channel, self->_i2c_address, 0x31, &int1_src))
243  {
244  continue;
245  }
246 
247  if(self->_irq_flag)
248  {
249  self->_irq_flag = 0;
250 
251  if (self->_event_handler != NULL)
252  {
253  self->_event_handler(self, TWR_LIS2DH12_EVENT_ALARM, self->_event_param);
254  }
255  }
256  }
257 
258  self->_state = TWR_LIS2DH12_STATE_MEASURE;
259 
260  return;
261  }
262  default:
263  {
264  self->_state = TWR_LIS2DH12_STATE_ERROR;
265 
266  continue;
267  }
268  }
269  }
270 }
271 
272 static bool _twr_lis2dh12_power_down(twr_lis2dh12_t *self)
273 {
274  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, 0x20, 0x07))
275  {
276  return false;
277  }
278 
279  return true;
280 }
281 
282 static bool _twr_lis2dh12_continuous_conversion(twr_lis2dh12_t *self)
283 {
284 
285  uint8_t cfg_reg1 = 0x57 | ((self->_resolution & 0x02) << 2);
286 
287  // ODR = 0x5 => 100Hz
288  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, 0x20, cfg_reg1))
289  {
290  return false;
291  }
292 
293  return true;
294 }
295 
296 static bool _twr_lis2dh12_read_result(twr_lis2dh12_t *self)
297 {
298  twr_i2c_memory_transfer_t transfer;
299 
300  transfer.device_address = self->_i2c_address;
301  transfer.memory_address = _TWR_LIS2DH12_AUTOINCREMENT_ADR | 0x28;
302  transfer.buffer = &self->_raw;
303  transfer.length = 6;
304 
305  return twr_i2c_memory_read(self->_i2c_channel, &transfer);
306 }
307 
309 {
310  if (alarm != NULL)
311  {
312  // Enable alarm
313  self->_alarm_active = true;
314 
315  // Disable IRQ first to change the registers
316  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, 0x30, 0x00))
317  {
318  return false;
319  }
320 
321  uint8_t int1_ths = (uint8_t)((alarm->threshold) / _twr_lis2dh12_ths_lut[self->_scale]);
322 
323  // Ensure minimum threshold level
324  if (int1_ths == 0)
325  {
326  int1_ths = 1;
327  }
328 
329  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, 0x32, int1_ths))
330  {
331  return false;
332  }
333 
334  uint8_t int1_duration = (uint8_t)(alarm->duration / 1); // /10
335  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, 0x33, int1_duration))
336  {
337  return false;
338  }
339 
340  // CTRL_REG3
341  uint8_t ctrl_reg3 = (1 << 6);
342  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, 0x22, ctrl_reg3))
343  {
344  return false;
345  }
346 
347  // CTRL_REG6 - invert interrupt
348  uint8_t ctrl_reg6 = (1 << 1);
349  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, 0x25, ctrl_reg6))
350  {
351  return false;
352  }
353 
354  // ctr_reg5
355  uint8_t ctrl_reg5 = (0 << 3); // latch interrupt request
356  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, 0x24, ctrl_reg5))
357  {
358  return false;
359  }
360 
361  // INT_CFG1
362  uint8_t int_cfg1;
363 
364  int_cfg1 = 0; //(1 << 7) | (1 << 6); // AOI = 0, 6D = 1
365 
366  int_cfg1 |= (alarm->z_high) ? (1 << 5) : 0;
367  int_cfg1 |= (alarm->z_low) ? (1 << 4) : 0;
368 
369  int_cfg1 |= (alarm->y_high) ? (1 << 3) : 0;
370  int_cfg1 |= (alarm->y_low) ? (1 << 2) : 0;
371 
372  int_cfg1 |= (alarm->x_high) ? (1 << 1) : 0;
373  int_cfg1 |= (alarm->x_low) ? (1 << 0) : 0;
374 
375  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, 0x30, int_cfg1))
376  {
377  return false;
378  }
379 
380  twr_exti_register(TWR_EXTI_LINE_PB6, TWR_EXTI_EDGE_FALLING, _twr_lis2dh12_interrupt, self);
381  }
382  else
383  {
384  // Disable alarm
385  self->_alarm_active = false;
386 
387  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, 0x30, 0x00))
388  {
389  return false;
390  }
391 
393  }
394 
395  twr_lis2dh12_measure(self);
396 
397  return true;
398 }
399 
401 {
402  self->_resolution = resolution;
403 
404  self->_state = TWR_LIS2DH12_STATE_INITIALIZE;
405 
406  twr_scheduler_plan_now(self->_task_id_measure);
407 
408  return true;
409 }
410 
412 {
413  self->_scale = scale;
414 
415  self->_state = TWR_LIS2DH12_STATE_INITIALIZE;
416 
417  twr_scheduler_plan_now(self->_task_id_measure);
418 
419  return true;
420 }
421 
422 static void _twr_lis2dh12_interrupt(twr_exti_line_t line, void *param)
423 {
424  (void) line;
425 
426  twr_lis2dh12_t *self = param;
427 
428  self->_irq_flag = true;
429 
430  twr_lis2dh12_measure(self);
431 }
void twr_exti_register(twr_exti_line_t line, twr_exti_edge_t edge, void(*callback)(twr_exti_line_t, void *), void *param)
Enable EXTI line interrupt and register callback function.
Definition: twr_exti.c:17
void twr_exti_unregister(twr_exti_line_t line)
Disable EXTI line interrupt.
Definition: twr_exti.c:90
twr_exti_line_t
EXTI lines.
Definition: twr_exti.h:22
@ TWR_EXTI_LINE_PB6
EXTI line PB6.
Definition: twr_exti.h:90
@ TWR_EXTI_EDGE_FALLING
EXTI line is configured to falling edge sensitivity.
Definition: twr_exti.h:201
void twr_i2c_init(twr_i2c_channel_t channel, twr_i2c_speed_t speed)
Initialize I2C channel.
Definition: twr_i2c.c:57
bool twr_i2c_memory_read(twr_i2c_channel_t channel, const twr_i2c_memory_transfer_t *transfer)
Memory read from I2C channel.
Definition: twr_i2c.c:371
bool twr_i2c_memory_write_8b(twr_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint8_t data)
Memory write 1 byte to I2C channel.
Definition: twr_i2c.c:408
bool twr_i2c_memory_read_8b(twr_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint8_t *data)
Memory read 1 byte from I2C channel.
Definition: twr_i2c.c:437
twr_i2c_channel_t
I2C channels.
Definition: twr_i2c.h:16
@ TWR_I2C_SPEED_400_KHZ
I2C communication speed is 400 kHz.
Definition: twr_i2c.h:36
twr_lis2dh12_resolution_t
Resolution and mode.
Definition: twr_lis2dh12.h:30
void twr_lis2dh12_set_event_handler(twr_lis2dh12_t *self, void(*event_handler)(twr_lis2dh12_t *, twr_lis2dh12_event_t, void *), void *event_param)
Set callback function.
Definition: twr_lis2dh12.c:57
bool twr_lis2dh12_measure(twr_lis2dh12_t *self)
Start measurement manually.
Definition: twr_lis2dh12.c:79
bool twr_lis2dh12_set_resolution(twr_lis2dh12_t *self, twr_lis2dh12_resolution_t resolution)
Set resolution.
Definition: twr_lis2dh12.c:400
twr_lis2dh12_event_t
Callback events.
Definition: twr_lis2dh12.h:15
void twr_lis2dh12_set_update_interval(twr_lis2dh12_t *self, twr_tick_t interval)
Set measurement interval.
Definition: twr_lis2dh12.c:63
twr_lis2dh12_scale_t
Definition: twr_lis2dh12.h:43
bool twr_lis2dh12_init(twr_lis2dh12_t *self, twr_i2c_channel_t i2c_channel, uint8_t i2c_address)
Initialize LIS2DH12.
Definition: twr_lis2dh12.c:33
struct twr_lis2dh12_t twr_lis2dh12_t
LIS2DH12 instance.
Definition: twr_lis2dh12.h:106
bool twr_lis2dh12_get_result_g(twr_lis2dh12_t *self, twr_lis2dh12_result_g_t *result_g)
Get measured acceleration in g.
Definition: twr_lis2dh12.c:100
bool twr_lis2dh12_get_result_raw(twr_lis2dh12_t *self, twr_lis2dh12_result_raw_t *result_raw)
Get measured acceleration as raw value.
Definition: twr_lis2dh12.c:93
bool twr_lis2dh12_set_scale(twr_lis2dh12_t *self, twr_lis2dh12_scale_t scale)
Set scale.
Definition: twr_lis2dh12.c:411
bool twr_lis2dh12_set_alarm(twr_lis2dh12_t *self, twr_lis2dh12_alarm_t *alarm)
Enable or disable accelerometer threshold alarm.
Definition: twr_lis2dh12.c:308
@ TWR_LIS2DH12_EVENT_ALARM
Alarm event.
Definition: twr_lis2dh12.h:23
@ TWR_LIS2DH12_EVENT_ERROR
Error event.
Definition: twr_lis2dh12.h:17
@ TWR_LIS2DH12_EVENT_UPDATE
Update event.
Definition: twr_lis2dh12.h:20
@ TWR_LIS2DH12_SCALE_4G
±4 g.
Definition: twr_lis2dh12.h:48
@ TWR_LIS2DH12_SCALE_16G
±16 g.
Definition: twr_lis2dh12.h:54
@ TWR_LIS2DH12_SCALE_8G
±8 g.
Definition: twr_lis2dh12.h:51
@ TWR_LIS2DH12_SCALE_2G
±2 g (Default)
Definition: twr_lis2dh12.h:45
void twr_scheduler_plan_current_from_now(twr_tick_t tick)
Schedule current task to tick relative from now.
void twr_scheduler_plan_current_relative(twr_tick_t tick)
Schedule current task to tick relative from current spin.
void twr_scheduler_plan_absolute(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to absolute tick.
void twr_scheduler_plan_now(twr_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
void twr_scheduler_plan_relative(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to tick relative from current spin.
twr_scheduler_task_id_t twr_scheduler_register(void(*task)(void *), void *param, twr_tick_t tick)
Register task in scheduler.
Definition: twr_scheduler.c:53
#define TWR_TICK_INFINITY
Maximum timestamp value.
Definition: twr_tick.h:12
uint64_t twr_tick_t
Timestamp data type.
Definition: twr_tick.h:16
I2C memory transfer parameters.
Definition: twr_i2c.h:58
uint32_t memory_address
8-bit I2C memory address (it can be extended to 16-bit format if OR-ed with TWR_I2C_MEMORY_ADDRESS_16...
Definition: twr_i2c.h:63
uint8_t device_address
7-bit I2C device address
Definition: twr_i2c.h:60
size_t length
Length of buffer which is being written or read.
Definition: twr_i2c.h:69
void * buffer
Pointer to buffer which is being written or read.
Definition: twr_i2c.h:66
LIS2DH12 alarm set structure.
Definition: twr_lis2dh12.h:91
float threshold
Alarm threshold in g.
Definition: twr_lis2dh12.h:93
LIS2DH12 result in g.
Definition: twr_lis2dh12.h:76
LIS2DH12 result in raw values.
Definition: twr_lis2dh12.h:61