Code
18 #include <ao.h>
19 #include <ao_mma655x.h>
20
21 #if HAS_MMA655X
22
23 #if 0
24 #define PRINTD(...) do { printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); } while(0)
25 #else
26 #define PRINTD(...)
27 #endif
28
29 static uint8_t mma655x_configured;
30
31 uint8_t ao_mma655x_spi_index = AO_MMA655X_SPI_INDEX;
32
33 static void
34 ao_mma655x_start(void) {
35 ao_spi_get_bit(AO_MMA655X_CS_PORT,
36 AO_MMA655X_CS_PIN,
37 AO_MMA655X_CS,
38 AO_MMA655X_SPI_INDEX,
39 AO_SPI_SPEED_FAST);
40 }
41
42 static void
43 ao_mma655x_stop(void) {
44 ao_spi_put_bit(AO_MMA655X_CS_PORT,
45 AO_MMA655X_CS_PIN,
46 AO_MMA655X_CS,
47 AO_MMA655X_SPI_INDEX);
48 }
49
50 static void
51 ao_mma655x_restart(void) {
52 uint8_t i;
53 ao_gpio_set(AO_MMA655X_CS_PORT, AO_MMA655X_CS_PIN, AO_MMA655X_CS, 1);
54
55 /* Emperical testing on STM32L151 at 32MHz for this delay amount */
56 for (i = 0; i < 9; i++)
57 ao_arch_nop();
58 ao_gpio_set(AO_MMA655X_CS_PORT, AO_MMA655X_CS_PIN, AO_MMA655X_CS, 0);
59 }
60
61 static uint8_t
62 ao_parity(uint8_t v)
63 {
64 uint8_t p;
65 /* down to four bits */
66 p = (v ^ (v >> 4)) & 0xf;
67
68 /* Cute lookup hack -- 0x6996 encodes the sixteen
69 * even parity values in order.
70 */
71 p = (~0x6996 >> p) & 1;
72 return p;
73 }
74
75 static void
76 ao_mma655x_cmd(uint8_t d[2])
77 {
78 ao_mma655x_start();
79 PRINTD("\tSEND %02x %02x\n", d[0], d[1]);
80 ao_spi_duplex(d, d, 2, AO_MMA655X_SPI_INDEX);
81 PRINTD("\t\tRECV %02x %02x\n", d[0], d[1]);
82 ao_mma655x_stop();
83 }
84
85 static uint8_t
86 ao_mma655x_reg_read(uint8_t addr)
87 {
88 uint8_t d[2];
89 ao_mma655x_start();
90 d[0] = addr | (ao_parity(addr) << 7);
91 d[1] = 0;
92 ao_spi_send(&d, 2, AO_MMA655X_SPI_INDEX);
93 ao_mma655x_restart();
94
95 /* Send a dummy read of 00 to clock out the SPI data */
96 d[0] = 0x80;
97 d[1] = 0x00;
98 ao_spi_duplex(&d, &d, 2, AO_MMA655X_SPI_INDEX);
99 ao_mma655x_stop();
100 return d[1];
101 }
102
103 static void
104 ao_mma655x_reg_write(uint8_t addr, uint8_t value)
105 {
106 uint8_t d[2];
107
108 addr |= (1 << 6); /* write mode */
109 d[0] = addr | (ao_parity(addr^value) << 7);
110 d[1] = value;
111 ao_mma655x_start();
112 ao_spi_send(d, 2, AO_MMA655X_SPI_INDEX);
113 ao_mma655x_stop();
114
115 addr &= ~(1 << 6);
116 PRINTD("write %x %x = %x\n",
117 addr, value, ao_mma655x_reg_read(addr));
118 }
119
120 static uint16_t
121 ao_mma655x_value(void)
122 {
123 uint8_t d[2];
124 uint16_t v;
125
126 d[0] = ((0 << 6) | /* Axis selection (X) */
127 (1 << 5) | /* Acceleration operation */
128 (1 << 4)); /* Raw data */
129 d[1] = ((1 << 3) | /* must be one */
130 (1 << 2) | /* Unsigned data */
131 (0 << 1) | /* Arm disabled */
132 (1 << 0)); /* Odd parity */
133 ao_mma655x_start();
134 PRINTD("value SEND %02x %02x\n", d[0], d[1]);
135 ao_spi_send(d, 2, AO_MMA655X_SPI_INDEX);
136 ao_mma655x_restart();
137 d[0] = 0x80;
138 d[1] = 0x00;
139 ao_spi_duplex(d, d, 2, AO_MMA655X_SPI_INDEX);
140 ao_mma655x_stop();
141 PRINTD("value RECV %02x %02x\n", d[0], d[1]);
142
143 v = (uint16_t) d[1] << 2;
144 v |= d[0] >> 6;
145 v |= (uint16_t) (d[0] & 3) << 10;
146 return v;
147 }
148
149 static void
150 ao_mma655x_reset(void) {
151 ao_mma655x_reg_write(AO_MMA655X_DEVCTL,
152 (0 << AO_MMA655X_DEVCTL_RES_1) |
153 (0 << AO_MMA655X_DEVCTL_RES_1));
154 ao_mma655x_reg_write(AO_MMA655X_DEVCTL,
155 (1 << AO_MMA655X_DEVCTL_RES_1) |
156 (1 << AO_MMA655X_DEVCTL_RES_1));
157 ao_mma655x_reg_write(AO_MMA655X_DEVCTL,
158 (0 << AO_MMA655X_DEVCTL_RES_1) |
159 (1 << AO_MMA655X_DEVCTL_RES_1));
160 }
161
162 #define DEVCFG_VALUE (\
163 (1 << AO_MMA655X_DEVCFG_OC) | /* Disable offset cancelation */ \
164 (1 << AO_MMA655X_DEVCFG_SD) | /* Receive unsigned data */ \
165 (0 << AO_MMA655X_DEVCFG_OFMON) | /* Disable offset monitor */ \
166 (AO_MMA655X_DEVCFG_A_CFG_DISABLE << AO_MMA655X_DEVCFG_A_CFG))
167
168 #define AXISCFG_VALUE (\
169 (0 << AO_MMA655X_AXISCFG_LPF)) /* 100Hz 4-pole filter */
170
171
172 static void
173 ao_mma655x_setup(void)
174 {
175 uint8_t v;
176 uint16_t a, a_st;
177 uint8_t stdefl;
178 uint8_t i;
179 uint8_t s0, s1, s2, s3;
180 uint8_t pn;
181 uint32_t lot;
182 uint16_t serial;
183
184
185 if (mma655x_configured)
186 return;
187 mma655x_configured = 1;
188 ao_delay(AO_MS_TO_TICKS(10)); /* Top */
189 ao_mma655x_reset();
190 ao_delay(AO_MS_TO_TICKS(10)); /* Top */
191 (void) ao_mma655x_reg_read(AO_MMA655X_DEVSTAT);
192 v = ao_mma655x_reg_read(AO_MMA655X_DEVSTAT);
193
194 /* Configure R/W register values.
195 * Most of them relate to the arming feature, which
196 * we don't use, so the only registers we need to
197 * write are DEVCFG and AXISCFG
198 */
199
200 ao_mma655x_reg_write(AO_MMA655X_DEVCFG,
201 DEVCFG_VALUE | (0 << AO_MMA655X_DEVCFG_ENDINIT));
202
203 /* Test X axis
204 */
205
206 ao_mma655x_reg_write(AO_MMA655X_AXISCFG,
207 AXISCFG_VALUE |
208 (1 << AO_MMA655X_AXISCFG_ST));
209 for (i = 0; i < 10; i++) {
210 a_st = ao_mma655x_value();
211 printf ("SELF-TEST %2d = %6d\n", i, a_st);
212 }
213
214 stdefl = ao_mma655x_reg_read(AO_MMA655X_STDEFL);
215
216 ao_mma655x_reg_write(AO_MMA655X_AXISCFG,
217 AXISCFG_VALUE |
218 (0 << AO_MMA655X_AXISCFG_ST));
219 a = ao_mma655x_value();
220
221 for (i = 0; i < 10; i++) {
222 a = ao_mma655x_value();
223 printf("NORMAL %2d = %6d\n", i, a);
224 }
225
226 ao_mma655x_reg_write(AO_MMA655X_DEVCFG,
227 DEVCFG_VALUE | (1 << AO_MMA655X_DEVCFG_ENDINIT));
228 s0 = ao_mma655x_reg_read(AO_MMA655X_SN0);
229 s1 = ao_mma655x_reg_read(AO_MMA655X_SN1);
230 s2 = ao_mma655x_reg_read(AO_MMA655X_SN2);
231 s3 = ao_mma655x_reg_read(AO_MMA655X_SN3);
232 lot = ((uint32_t) s3 << 24) | ((uint32_t) s2 << 16) |
233 ((uint32_t) s1 << 8) | ((uint32_t) s0);
234 serial = lot & 0x1fff;
235 lot >>= 12;
236 pn = ao_mma655x_reg_read(AO_MMA655X_PN);
237 printf ("MMA655X lot %d serial %d number %d\n", lot, serial, pn);
238
239 }
240
241 uint16_t ao_mma655x_current;
242
243 static void
244 ao_mma655x_dump(void)
245 {
246 printf ("MMA655X value %d\n", ao_mma655x_current);
247 }
248
249 __code struct ao_cmds ao_mma655x_cmds[] = {
250 { ao_mma655x_dump, "A\0Display MMA655X data" },
251 { 0, NULL },
252 };
253
254 static void
255 ao_mma655x(void)
256 {
257 ao_mma655x_setup();
258 for (;;) {
259 ao_mma655x_current = ao_mma655x_value();
260 ao_arch_critical(
261 AO_DATA_PRESENT(AO_DATA_MMA655X);
262 AO_DATA_WAIT();
263 );
264 }
265 }
266
267 static __xdata struct ao_task ao_mma655x_task;
268
269 void
270 ao_mma655x_init(void)
271 {
272 mma655x_configured = 0;
273
274 ao_cmd_register(&ao_mma655x_cmds[0]);
275 ao_spi_init_cs(AO_MMA655X_CS_PORT, (1 << AO_MMA655X_CS_PIN));
276
277 ao_add_task(&ao_mma655x_task, ao_mma655x, "mma655x");
278 }
279
280 #endif
Da wird erst ein Reset (line 189)gesendet, dann 2x das DEVSTAT Register gelesen (191+192).
Das habe ich auch schon probiert, leider ohne Erfolg.