forked from Klipper3d/klipper
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sensor_lis3dh.c
163 lines (143 loc) · 4.54 KB
/
sensor_lis3dh.c
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
#include <string.h> // memcpy
#include "board/irq.h" // irq_disable
#include "board/misc.h" // timer_read_time
#include "basecmd.h" // oid_alloc
#include "command.h" // DECL_COMMAND
#include "sched.h" // DECL_TASK
#include "sensor_bulk.h" // sensor_bulk_report
#include "spicmds.h" // spidev_transfer
#define LIS_AR_DATAX0 0x28
#define LIS_AM_READ 0x80
#define FIFO_CTRL_REG 0x2E
#define FIFO_SRC_REG 0x2F
#define BYTES_PER_SAMPLE 6
struct lis3dh {
struct timer timer;
uint32_t rest_ticks;
struct spidev_s *spi;
uint8_t flags;
struct sensor_bulk sb;
};
#define FIFO_SRC_REG_WTM(val) ((val)&(1<<7))
#define FIFO_SRC_REG_OVRN(val) ((val)&(1<<6))
#define FIFO_SRC_REG_EMPTY(val) ((val)&(1<<5))
#define FIFO_SRC_REG_FSS(val) ((val)&0x1F)
enum {
LIS_PENDING = 1<<0,
};
static struct task_wake lis3dh_wake;
// Event handler that wakes lis3dh_task() periodically
static uint_fast8_t
lis3dh_event(struct timer *timer)
{
struct lis3dh *ax = container_of(timer, struct lis3dh, timer);
ax->flags |= LIS_PENDING;
sched_wake_task(&lis3dh_wake);
return SF_DONE;
}
void
command_config_lis3dh(uint32_t *args)
{
struct lis3dh *ax = oid_alloc(args[0], command_config_lis3dh
, sizeof(*ax));
ax->timer.func = lis3dh_event;
ax->spi = spidev_oid_lookup(args[1]);
}
DECL_COMMAND(command_config_lis3dh, "config_lis3dh oid=%c spi_oid=%c");
// Helper code to reschedule the lis3dh_event() timer
static void
lis3dh_reschedule_timer(struct lis3dh *ax)
{
irq_disable();
ax->timer.waketime = timer_read_time() + ax->rest_ticks;
sched_add_timer(&ax->timer);
irq_enable();
}
// Query accelerometer data
static void
lis3dh_query(struct lis3dh *ax, uint8_t oid)
{
uint8_t msg[2] = {0,0};
uint8_t *d = &ax->sb.data[ax->sb.data_count];
msg[0] = 0x28 | LIS_AM_READ ;
spidev_transfer(ax->spi, 1, sizeof(msg), msg);
d[0] = msg[1]; // x low bits
msg[0] = 0x29 | LIS_AM_READ ;
spidev_transfer(ax->spi, 1, sizeof(msg), msg);
d[1] = msg[1]; // x high bits
msg[0] = 0x2A | LIS_AM_READ ;
spidev_transfer(ax->spi, 1, sizeof(msg), msg);
d[2] = msg[1]; // y low bits
msg[0] = 0x2B | LIS_AM_READ ;
spidev_transfer(ax->spi, 1, sizeof(msg), msg);
d[3] = msg[1]; // y high bits
msg[0] = 0x2C | LIS_AM_READ ;
spidev_transfer(ax->spi, 1, sizeof(msg), msg);
d[4] = msg[1]; // z low bits
msg[0] = 0x2D | LIS_AM_READ ;
spidev_transfer(ax->spi, 1, sizeof(msg), msg);
d[5] = msg[1]; // z high bits
ax->sb.data_count += BYTES_PER_SAMPLE;
if (ax->sb.data_count + BYTES_PER_SAMPLE > ARRAY_SIZE(ax->sb.data))
sensor_bulk_report(&ax->sb, oid);
uint8_t fifo[2] = {FIFO_SRC_REG| LIS_AM_READ,0};
spidev_transfer(ax->spi, 1, sizeof(fifo), fifo);
uint8_t reg_val = fifo[1];
// Check fifo status
if (FIFO_SRC_REG_OVRN(reg_val))
ax->sb.possible_overflows++;
// check if we need to run the task again (more packets in fifo?)
if (!FIFO_SRC_REG_EMPTY(reg_val)) {
// More data in fifo - wake this task again
sched_wake_task(&lis3dh_wake);
} else {
// Sleep until next check time
ax->flags &= ~LIS_PENDING;
lis3dh_reschedule_timer(ax);
}
}
void
command_query_lis3dh(uint32_t *args)
{
struct lis3dh *ax = oid_lookup(args[0], command_config_lis3dh);
sched_del_timer(&ax->timer);
ax->flags = 0;
if (!args[1])
// End measurements
return;
// Start new measurements query
ax->rest_ticks = args[1];
sensor_bulk_reset(&ax->sb);
lis3dh_reschedule_timer(ax);
}
DECL_COMMAND(command_query_lis3dh, "query_lis3dh oid=%c rest_ticks=%u");
void
command_query_lis3dh_status(uint32_t *args)
{
struct lis3dh *ax = oid_lookup(args[0], command_config_lis3dh);
uint8_t msg[2] = { FIFO_SRC_REG | LIS_AM_READ, 0x00 };
uint32_t time1 = timer_read_time();
spidev_transfer(ax->spi, 1, sizeof(msg), msg);
uint32_t time2 = timer_read_time();
uint_fast8_t fifo_status = FIFO_SRC_REG_FSS(msg[1]);
if(FIFO_SRC_REG_OVRN(msg[1]))
fifo_status = 32;
fifo_status&=32;
sensor_bulk_status(&ax->sb, args[0], time1, time2-time1
, fifo_status * BYTES_PER_SAMPLE);
}
DECL_COMMAND(command_query_lis3dh_status, "query_lis3dh_status oid=%c");
void
lis3dh_task(void)
{
if (!sched_check_wake(&lis3dh_wake))
return;
uint8_t oid;
struct lis3dh *ax;
foreach_oid(oid, ax, command_config_lis3dh) {
uint_fast8_t flags = ax->flags;
if (flags & LIS_PENDING)
lis3dh_query(ax, oid);
}
}
DECL_TASK(lis3dh_task);