2 #include <msp430xgeneric.h>
11 #include "oswald_main.h"
13 #define ACCEL_STATE_DISABLED 0x00
14 #define ACCEL_STATE_ENABLED 0x01
16 static uint8_t AccelState;
17 static uint8_t AccelerometerBusy;
18 static uint8_t LengthCount;
20 static uint8_t *pAccelerometerData;
23 * Accelerometer is a Kionix KXTF9-4100 connected to I2C
24 * I2C is pretty slow so reading and writing should be done non blocking
28 #define ACCELEROMETER_NO_INTERRUPTS 0x00
29 #define ACCELEROMETER_ALIFG 0x02
30 #define ACCELEROMETER_NACKIFG 0x04
31 #define ACCELEROMETER_STTIFG 0x06
32 #define ACCELEROMETER_STPIFG 0x08
33 #define ACCELEROMETER_RXIFG 0x0a
34 #define ACCELEROMETER_TXIFG 0x0c
36 #pragma vector=USCI_B1_VECTOR
37 __interrupt void ACCERLEROMETER_I2C_ISR(void)
39 // debug_uart_tx("ACC i2c irq\n");
40 switch (USCI_ACCELEROMETER_IV) {
41 case ACCELEROMETER_NO_INTERRUPTS:
43 case ACCELEROMETER_ALIFG:
45 case ACCELEROMETER_NACKIFG:
48 case ACCELEROMETER_STTIFG:
51 case ACCELEROMETER_STPIFG:
53 case ACCELEROMETER_RXIFG:
54 if (LengthCount > 0) {
55 pAccelerometerData[Index++] = ACCELEROMETER_RXBUF;
57 if ( LengthCount == 1 ) {
58 /* All but one byte received. Send stop */
59 ACCELEROMETER_CTL1 |= UCTXSTP;
60 } else if ( LengthCount == 0 ) {
61 /* Last byte received; disable rx interrupt */
62 ACCELEROMETER_IE &= ~UCRXIE;
63 AccelerometerBusy = 0;
67 case ACCELEROMETER_TXIFG:
68 if ( LengthCount > 0 ) {
69 ACCELEROMETER_TXBUF = pAccelerometerData[Index++];
72 /* disable transmit interrupt and send stop */
73 ACCELEROMETER_IE &= ~UCTXIE;
74 ACCELEROMETER_CTL1 |= UCTXSTP;
75 AccelerometerBusy = 0;
84 void mw_acc_init_i2c(void)
86 /* enable reset before configuration */
87 ACCELEROMETER_CTL1 |= UCSWRST;
89 /* configure as master using smclk / 40 = 399.5 kHz */
90 ACCELEROMETER_CTL0 = UCMST + UCMODE_3 + UCSYNC;
91 ACCELEROMETER_CTL1 = UCSSEL__SMCLK + UCSWRST;
92 ACCELEROMETER_BR0 = 42;
94 ACCELEROMETER_BR1 = 0;
95 ACCELEROMETER_I2CSA = KIONIX_DEVICE_ADDRESS;
98 ACCELEROMETER_CTL1 &= ~UCSWRST;
101 void mw_acc_disable_i2c(void)
103 /* enable reset to hold it */
104 ACCELEROMETER_CTL1 |= UCSWRST;
107 void mw_acc_i2c_write(uint8_t RegisterAddress, uint8_t *pData, uint8_t Length)
109 if (Length == 0 || pData == 0)
112 while (UCB1STAT & UCBBUSY)
115 AccelerometerBusy = 1;
116 LengthCount = Length;
118 pAccelerometerData = pData;
121 * enable transmit interrupt and
122 * setup for write and send the start condition
124 ACCELEROMETER_IFG = 0;
125 ACCELEROMETER_CTL1 |= UCTR + UCTXSTT;
126 while(!(ACCELEROMETER_IFG & UCTXIFG))
130 * clear transmit interrupt flag, enable interrupt,
131 * send the register address
133 ACCELEROMETER_IFG = 0;
134 ACCELEROMETER_IE |= UCTXIE;
135 ACCELEROMETER_TXBUF = RegisterAddress;
137 while (AccelerometerBusy)
140 while (ACCELEROMETER_CTL1 & UCTXSTP)
143 /* the rest of TX will be handled by the ISR */
146 void mw_acc_i2c_read_single(const uint8_t RegisterAddress, const uint8_t *pData)
151 /* wait for bus to be free */
152 while (UCB1STAT & UCBBUSY)
155 AccelerometerBusy = 1;
158 pAccelerometerData = (uint8_t *)pData;
160 /* transmit address */
161 ACCELEROMETER_IFG = 0;
162 ACCELEROMETER_CTL1 |= UCTR + UCTXSTT;
163 while (!(ACCELEROMETER_IFG & UCTXIFG))
166 /* write register address */
167 ACCELEROMETER_IFG = 0;
168 ACCELEROMETER_TXBUF = RegisterAddress;
169 while (!(ACCELEROMETER_IFG & UCTXIFG))
172 /* send a repeated start (same slave address now it is a read command)
173 * read possible extra character from rxbuffer
176 ACCELEROMETER_IFG = 0;
177 ACCELEROMETER_IE |= UCRXIE;
178 ACCELEROMETER_CTL1 &= ~UCTR;
179 /* for a read of a single byte the stop must be sent while the byte is being
180 * received. If this is interrupted an extra byte may be read.
181 * however, it will be discarded during the next read
183 if ( LengthCount == 1 ) {
184 /* errata usci30: prevent interruption of sending stop
185 * so that only one byte is read
186 * this requires 62 us @ 320 kHz, 51 @ 400 kHz
188 ACCELEROMETER_CTL1 |= UCTXSTT;
190 while(ACCELEROMETER_CTL1 & UCTXSTT)
193 ACCELEROMETER_CTL1 |= UCTXSTP;
195 ACCELEROMETER_CTL1 |= UCTXSTT;
198 /* wait until all data has been received and the stop bit has been sent */
199 while (AccelerometerBusy)
201 while (ACCELEROMETER_CTL1 & UCTXSTP)
204 pAccelerometerData = 0;
207 /* errata usci30: only perform single reads
208 * second solution: use DMA
210 void mw_acc_i2c_read(const uint8_t RegisterAddress, uint8_t *pData, const uint8_t Length)
214 for ( i = 0; i < Length; i++ ) {
215 mw_acc_i2c_read_single(RegisterAddress + i, (pData + i));
220 void mw_acc_init(void)
222 uint8_t WriteRegisterData;
223 uint8_t pReadRegisterData[4];
224 #if defined MW_DEVBOARD_V2
228 ENABLE_ACCELEROMETER_POWER();
233 * make sure part is in standby mode because some registers can only
234 * be changed when the part is not active.
236 WriteRegisterData = PC1_STANDBY_MODE;
237 mw_acc_i2c_write(KIONIX_CTRL_REG1, &WriteRegisterData, 1);
239 /* enable face-up and face-down detection */
240 WriteRegisterData = TILT_FDM | TILT_FUM;
241 mw_acc_i2c_write(KIONIX_CTRL_REG2, &WriteRegisterData, 1);
244 * the interrupt from the accelerometer can be used to get periodic data
245 * the real time clock can also be used
248 /* change to output data rate to 25 Hz */
249 WriteRegisterData = WUF_ODR_25HZ | TAP_ODR_400HZ;
250 mw_acc_i2c_write(KIONIX_CTRL_REG3, &WriteRegisterData, 1);
252 /* enable interrupt and make it active high */
253 WriteRegisterData = IEN | IEA;
254 mw_acc_i2c_write(KIONIX_INT_CTRL_REG1, &WriteRegisterData, 1);
256 /* enable motion detection interrupt for all three axis */
257 WriteRegisterData = XBW | YBW | ZBW;
258 mw_acc_i2c_write(KIONIX_INT_CTRL_REG2, &WriteRegisterData, 1);
260 /* enable tap interrupt for Z-axis */
261 WriteRegisterData = TFDM;
262 mw_acc_i2c_write(KIONIX_INT_CTRL_REG3, &WriteRegisterData, 1);
264 /* set TDT_TIMER to 0.2 secs*/
265 WriteRegisterData = 0x50;
266 mw_acc_i2c_write(KIONIX_TDT_TIMER, &WriteRegisterData, 1);
268 /* set tap low and high thresholds (default: 26 and 182) */
269 WriteRegisterData = 40; //78;
270 mw_acc_i2c_write(KIONIX_TDT_L_THRESH, &WriteRegisterData, 1);
271 WriteRegisterData = 128;
272 mw_acc_i2c_write(KIONIX_TDT_H_THRESH, &WriteRegisterData, 1);
274 /* set WUF_TIMER counter */
275 WriteRegisterData = 10;
276 mw_acc_i2c_write(KIONIX_WUF_TIMER, &WriteRegisterData, 1);
278 /* this causes data to always be sent */
279 // WriteRegisterData = 0x00;
280 WriteRegisterData = 0x02 /*0x08*/;
281 mw_acc_i2c_write(KIONIX_WUF_THRESH, &WriteRegisterData, 1);
283 /* single byte read test */
284 mw_acc_i2c_read(KIONIX_DCST_RESP, pReadRegisterData, 1);
285 #if defined MW_DEVBOARD_V2
286 snprintf(tstr, 16, "acc DCST 0x%02x\n", pReadRegisterData[0]);
290 /* multiple byte read test */
291 mw_acc_i2c_read(KIONIX_WHO_AM_I, pReadRegisterData, 2);
292 #if defined MW_DEVBOARD_V2
293 snprintf(tstr, 16, "acc is 0x%02x 0x%02x\n", pReadRegisterData[0], pReadRegisterData[1]);
298 * KIONIX_CTRL_REG3 and DATA_CTRL_REG can remain at their default values
303 /* KTXF9 300 uA; KTXI9 165 uA */
304 WriteRegisterData = PC1_OPERATING_MODE | TAP_ENABLE_TDTE;
306 /* 180 uA; KTXI9 115 uA */
307 WriteRegisterData = PC1_OPERATING_MODE | RESOLUTION_8BIT | WUF_ENABLE;
309 /* 180 uA; KTXI9 8.7 uA */
310 WriteRegisterData = PC1_OPERATING_MODE | TILT_ENABLE_TPE;
312 /* 720 uA; KTXI9 330 uA */
313 WriteRegisterData = PC1_OPERATING_MODE | RESOLUTION_12BIT | WUF_ENABLE;
316 /* setup the default for the AccelerometerEnable command */
318 OperatingModeRegister = PC1_OPERATING_MODE | RESOLUTION_12BIT | TAP_ENABLE_TDTE | TILT_ENABLE_TPE; // | WUF_ENABLE;
319 InterruptControl = INTERRUPT_CONTROL_DISABLE_INTERRUPT;
320 SidControl = SID_CONTROL_SEND_DATA;
321 SidAddr = KIONIX_XOUT_L;
322 SidLength = XYZ_DATA_LENGTH;
324 AccelState = ACCEL_STATE_INIT;
328 void mw_acc_enable(void)
334 sdata = PC1_OPERATING_MODE | RESOLUTION_12BIT | TAP_ENABLE_TDTE | TILT_ENABLE_TPE | WUF_ENABLE;
335 //sdata = PC1_OPERATING_MODE | RESOLUTION_8BIT | TAP_ENABLE_TDTE | TILT_ENABLE_TPE; // | WUF_ENABLE;
336 mw_acc_i2c_write(KIONIX_CTRL_REG1, &sdata, 1);
338 ACCELEROMETER_INT_ENABLE();
339 mw_acc_i2c_read(KIONIX_INT_REL, &sdata, 1);
340 AccelState = ACCEL_STATE_ENABLED;
343 void mw_acc_disable(void)
347 if (AccelState == ACCEL_STATE_ENABLED) {
348 sdata = PC1_STANDBY_MODE;
349 mw_acc_i2c_write(KIONIX_CTRL_REG1, &sdata, 1);
351 ACCELEROMETER_INT_DISABLE();
352 mw_acc_disable_i2c();
353 DISABLE_ACCELEROMETER_POWER();
354 AccelState = ACCEL_STATE_DISABLED;
358 void mw_acc_read(int16_t *x, int16_t *y, int16_t *z)
362 if (AccelState == ACCEL_STATE_ENABLED) {
363 mw_acc_i2c_read(KIONIX_XOUT_L, rdata, 6);
365 *x = rdata[0] | (rdata[1] << 8);
366 *y = rdata[2] | (rdata[3] << 8);
367 *z = rdata[4] | (rdata[5] << 8);
375 void mw_acc_handle_irq(void)
377 uint8_t sdata, srcreg1, srcreg2;
378 #if defined MW_DEVBOARD_V2
382 if (AccelState != ACCEL_STATE_ENABLED)
385 mw_acc_i2c_read(KIONIX_INT_SRC_REG1, &srcreg1, 1);
386 #if defined MW_DEVBOARD_V2
387 snprintf(tstr, 16, "accsrc1: 0x%02x\n", srcreg1);
390 mw_acc_i2c_read(KIONIX_INT_SRC_REG2, &srcreg2, 1);
391 #if defined MW_DEVBOARD_V2
392 snprintf(tstr, 16, "accsrc2: 0x%02x\n", srcreg2);
395 if (srcreg1 & INT_TAP_SINGLE) {
397 if (srcreg1 & INT_TAP_DOUBLE) {
399 if (srcreg2 & INT_WUFS) {
401 mw_acc_read(&x, &y, &z);
402 oswald_handle_accel_event((int8_t)(x / (32768 / 255)), (int8_t)(y / (32768 / 255)), (int8_t)(z / (32768 / 255)));
405 mw_acc_i2c_read(KIONIX_INT_REL, &sdata, 1);