2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
5 * @addtogroup PIOS_BMA180 BMA180 Functions
6 * @brief Deals with the hardware interface to the BMA180 3-axis accelerometer
10 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
11 * @brief PiOS BMA180 digital accelerometer driver.
12 * - Driver for the BMA180 digital accelerometer on the SPI bus.
13 * @see The GNU Public License (GPL) Version 3
15 *****************************************************************************/
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 3 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 * You should have received a copy of the GNU General Public License along
28 * with this program; if not, write to the Free Software Foundation, Inc.,
29 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 #ifdef PIOS_INCLUDE_BMA180
36 #include "fifo_buffer.h"
38 enum pios_bma180_dev_magic
{
39 PIOS_BMA180_DEV_MAGIC
= 0xcbb93755,
42 #define PIOS_BMA180_MAX_DOWNSAMPLE 10
46 int16_t buffer
[PIOS_BMA180_MAX_DOWNSAMPLE
* sizeof(struct pios_bma180_data
)];
48 const struct pios_bma180_cfg
*cfg
;
49 enum bma180_bandwidth bandwidth
;
50 enum bma180_range range
;
51 enum pios_bma180_dev_magic magic
;
54 // ! Global structure for this device device
55 static struct bma180_dev
*dev
;
57 // ! Private functions
58 static struct bma180_dev
*PIOS_BMA180_alloc(void);
59 static int32_t PIOS_BMA180_Validate(struct bma180_dev
*dev
);
60 static int32_t PIOS_BMA180_GetReg(uint8_t reg
);
61 static int32_t PIOS_BMA180_SetReg(uint8_t reg
, uint8_t data
);
62 static int32_t PIOS_BMA180_SelectBW(enum bma180_bandwidth bw
);
63 static int32_t PIOS_BMA180_SetRange(enum bma180_range range
);
64 static int32_t PIOS_BMA180_Config();
65 static int32_t PIOS_BMA180_EnableIrq();
70 * @brief Allocate a new device
72 static struct bma180_dev
*PIOS_BMA180_alloc(void)
74 struct bma180_dev
*bma180_dev
;
76 bma180_dev
= (struct bma180_dev
*)pios_malloc(sizeof(*bma180_dev
));
81 fifoBuf_init(&bma180_dev
->fifo
, (uint8_t *)bma180_dev
->buffer
, sizeof(bma180_dev
->buffer
));
83 bma180_dev
->magic
= PIOS_BMA180_DEV_MAGIC
;
88 * @brief Validate the handle to the spi device
89 * @returns 0 for valid device or -1 otherwise
91 static int32_t PIOS_BMA180_Validate(struct bma180_dev
*vdev
)
96 if (vdev
->magic
!= PIOS_BMA180_DEV_MAGIC
) {
99 if (vdev
->spi_id
== 0) {
106 * @brief Initialize with good default settings
107 * @returns 0 for success, -1 for failure
109 int32_t PIOS_BMA180_Init(uint32_t spi_id
, uint32_t slave_num
, const struct pios_bma180_cfg
*cfg
)
111 dev
= PIOS_BMA180_alloc();
116 dev
->spi_id
= spi_id
;
117 dev
->slave_num
= slave_num
;
120 if (PIOS_BMA180_Config() < 0) {
123 PIOS_DELAY_WaituS(50);
125 PIOS_EXTI_Init(dev
->cfg
->exti_cfg
);
127 while (PIOS_BMA180_EnableIrq() != 0) {
135 * @brief Claim the SPI bus for the accel communications and select this chip
136 * @return 0 if successful, -1 if unable to claim bus
138 int32_t PIOS_BMA180_ClaimBus()
140 if (PIOS_BMA180_Validate(dev
) != 0) {
144 if (PIOS_SPI_ClaimBus(dev
->spi_id
) != 0) {
148 PIOS_SPI_RC_PinSet(dev
->spi_id
, dev
->slave_num
, 0);
154 * @brief Claim the SPI bus for the accel communications and select this chip. Call from an ISR.
155 * @param woken[in,out] If non-NULL, will be set to true if woken was false and a higher priority
156 * task has is now eligible to run, else unchanged
157 * @return 0 if successful, -1 if unable to claim bus
159 int32_t PIOS_BMA180_ClaimBusISR(bool *woken
)
161 if (PIOS_BMA180_Validate(dev
) != 0) {
165 if (PIOS_SPI_ClaimBusISR(dev
->spi_id
, woken
) != 0) {
169 PIOS_SPI_RC_PinSet(dev
->spi_id
, dev
->slave_num
, 0);
174 * @brief Release the SPI bus for the accel communications and end the transaction
175 * @return 0 if successful
177 int32_t PIOS_BMA180_ReleaseBus()
179 if (PIOS_BMA180_Validate(dev
) != 0) {
182 PIOS_SPI_RC_PinSet(dev
->spi_id
, dev
->slave_num
, 1);
184 return PIOS_SPI_ReleaseBus(dev
->spi_id
);
188 * @brief Release the SPI bus for the accel communications and end the transaction. Call from an ISR
189 * @param woken[in,out] If non-NULL, will be set to true if woken was false and a higher priority
190 * task has is now eligible to run, else unchanged
191 * @return 0 if successful
193 int32_t PIOS_BMA180_ReleaseBusISR(bool *woken
)
195 if (PIOS_BMA180_Validate(dev
) != 0) {
199 PIOS_SPI_RC_PinSet(dev
->spi_id
, dev
->slave_num
, 1);
201 return PIOS_SPI_ReleaseBusISR(dev
->spi_id
, woken
);
205 * @brief Read a register from BMA180
206 * @returns The register value or -1 if failure to get bus
207 * @param reg[in] Register address to be read
209 int32_t PIOS_BMA180_GetReg(uint8_t reg
)
211 if (PIOS_BMA180_Validate(dev
) != 0) {
217 if (PIOS_BMA180_ClaimBus() != 0) {
221 PIOS_SPI_TransferByte(dev
->spi_id
, (0x80 | reg
)); // request byte
222 data
= PIOS_SPI_TransferByte(dev
->spi_id
, 0); // receive response
224 PIOS_BMA180_ReleaseBus();
229 * @brief Write a BMA180 register. EEPROM must be unlocked before calling this function.
231 * @param reg[in] address of register to be written
232 * @param data[in] data that is to be written to register
234 int32_t PIOS_BMA180_SetReg(uint8_t reg
, uint8_t data
)
236 if (PIOS_BMA180_ClaimBus() != 0) {
240 PIOS_SPI_TransferByte(dev
->spi_id
, 0x7f & reg
);
241 PIOS_SPI_TransferByte(dev
->spi_id
, data
);
243 PIOS_BMA180_ReleaseBus();
249 static int32_t PIOS_BMA180_EnableEeprom()
251 // Enable EEPROM writing
252 int32_t byte
= PIOS_BMA180_GetReg(BMA_CTRREG0
);
257 byte
|= 0x10; // Set bit 4
258 if (PIOS_BMA180_SetReg(BMA_CTRREG0
, (uint8_t)byte
) < 0) { // Have to set ee_w to
264 static int32_t PIOS_BMA180_DisableEeprom()
266 // Enable EEPROM writing
267 int32_t byte
= PIOS_BMA180_GetReg(BMA_CTRREG0
);
272 byte
|= 0x10; // Set bit 4
273 if (PIOS_BMA180_SetReg(BMA_CTRREG0
, (uint8_t)byte
) < 0) { // Have to set ee_w to
280 * @brief Set the default register settings
281 * @return 0 if successful, -1 if not
283 static int32_t PIOS_BMA180_Config()
286 0x35 = 0x81 //smp-skip = 1 for less interrupts
287 0x33 = 0x81 //shadow-dis = 1, update MSB and LSB synchronously
288 0x27 = 0x01 //dis-i2c
289 0x21 = 0x02 //new_data_int = 1
292 PIOS_DELAY_WaituS(20);
294 if (PIOS_BMA180_Validate(dev
) != 0) {
298 while (PIOS_BMA180_EnableEeprom() != 0) {
301 while (PIOS_BMA180_SetReg(BMA_RESET
, BMA_RESET_CODE
) != 0) {
304 while (PIOS_BMA180_SetReg(BMA_OFFSET_LSB1
, 0x81) != 0) {
307 while (PIOS_BMA180_SetReg(BMA_GAIN_Y
, 0x81) != 0) {
310 while (PIOS_BMA180_SetReg(BMA_CTRREG3
, 0xFF) != 0) {
313 while (PIOS_BMA180_SelectBW(dev
->cfg
->bandwidth
) != 0) {
316 while (PIOS_BMA180_SetRange(dev
->cfg
->range
) != 0) {
319 while (PIOS_BMA180_DisableEeprom() != 0) {
327 * @brief Select the bandwidth the digital filter pass allows.
328 * @return 0 if successful, -1 if not
329 * @param rate[in] Bandwidth setting to be used
331 * EEPROM must be write-enabled before calling this function.
333 static int32_t PIOS_BMA180_SelectBW(enum bma180_bandwidth bw
)
335 if (PIOS_BMA180_Validate(dev
) != 0) {
342 reg
= PIOS_BMA180_GetReg(BMA_BW_ADDR
);
343 reg
= (reg
& ~BMA_BW_MASK
) | ((bw
<< BMA_BW_SHIFT
) & BMA_BW_MASK
);
344 return PIOS_BMA180_SetReg(BMA_BW_ADDR
, reg
);
348 * @brief Select the full scale acceleration range.
349 * @return 0 if successful, -1 if not
350 * @param rate[in] Range setting to be used
353 static int32_t PIOS_BMA180_SetRange(enum bma180_range new_range
)
355 if (PIOS_BMA180_Validate(dev
) != 0) {
361 dev
->range
= new_range
;
362 reg
= PIOS_BMA180_GetReg(BMA_RANGE_ADDR
);
363 reg
= (reg
& ~BMA_RANGE_MASK
) | ((dev
->range
<< BMA_RANGE_SHIFT
) & BMA_RANGE_MASK
);
364 return PIOS_BMA180_SetReg(BMA_RANGE_ADDR
, reg
);
367 static int32_t PIOS_BMA180_EnableIrq()
369 if (PIOS_BMA180_EnableEeprom() < 0) {
373 if (PIOS_BMA180_SetReg(BMA_CTRREG3
, BMA_NEW_DAT_INT
) < 0) {
377 if (PIOS_BMA180_DisableEeprom() < 0) {
385 * @brief Read a single set of values from the x y z channels
386 * @param[out] data Int16 array of (x,y,z) sensor values
387 * @returns 0 if successful
388 * @retval -1 unable to claim bus
389 * @retval -2 unable to transfer data
391 int32_t PIOS_BMA180_ReadAccels(struct pios_bma180_data
*data
)
393 // To save memory use same buffer for in and out but offset by
395 uint8_t buf
[7] = { BMA_X_LSB_ADDR
| 0x80, 0, 0, 0, 0, 0 };
396 uint8_t rec
[7] = { 0, 0, 0, 0, 0, 0 };
398 if (PIOS_BMA180_ClaimBus() != 0) {
401 if (PIOS_SPI_TransferBlock(dev
->spi_id
, &buf
[0], &rec
[0], 7, NULL
) != 0) {
404 PIOS_BMA180_ReleaseBus();
406 // | MSB | LSB | 0 | new_data |
407 data
->x
= ((rec
[2] << 8) | rec
[1]);
408 data
->y
= ((rec
[4] << 8) | rec
[3]);
409 data
->z
= ((rec
[6] << 8) | rec
[5]);
414 return 0; // return number of remaining entries
418 * @brief Returns the scale the BMA180 chip is using
419 * @return Scale (m / s^2) / LSB
421 float PIOS_BMA180_GetScale()
423 if (PIOS_BMA180_Validate(dev
) != 0) {
427 switch (dev
->cfg
->range
) {
429 return GRAV
/ 8192.0f
;
432 return GRAV
/ 5460.0f
;
435 return GRAV
/ 4096.0f
;
438 return GRAV
/ 2730.0f
;
441 return GRAV
/ 2048.0f
;
444 return GRAV
/ 1024.0f
;
447 return GRAV
/ 512.0f
;
453 * @brief Get data from fifo
454 * @param [out] buffer pointer to a @ref pios_bma180_data structure to receive data
455 * @return 0 for success, -1 for failure (no data available)
457 int32_t PIOS_BMA180_ReadFifo(struct pios_bma180_data
*buffer
)
459 if (PIOS_BMA180_Validate(dev
) != 0) {
463 if (fifoBuf_getUsed(&dev
->fifo
) < sizeof(*buffer
)) {
467 fifoBuf_getData(&dev
->fifo
, (uint8_t *)buffer
, sizeof(*buffer
));
474 * @brief Test SPI and chip functionality by reading chip ID register
475 * @return 0 if success, -1 if failure.
478 int32_t PIOS_BMA180_Test()
480 // Read chip ID then version ID
481 uint8_t buf
[3] = { 0x80 | BMA_CHIPID_ADDR
, 0, 0 };
482 uint8_t rec
[3] = { 0, 0, 0 };
485 if (PIOS_BMA180_ClaimBus() != 0) {
488 retval
= PIOS_SPI_TransferBlock(dev
->spi_id
, &buf
[0], &rec
[0], sizeof(buf
), NULL
);
489 PIOS_BMA180_ReleaseBus();
495 struct pios_bma180_data data
;
496 if (PIOS_BMA180_ReadAccels(&data
) != 0) {
512 * @brief EXTI IRQ Handler. Read data from the BMA180 FIFO and push onto a local fifo.
513 * @return a boolean to the EXTI IRQ Handler wrapper indicating if a
514 * higher priority task is now eligible to run
516 int32_t bma180_irqs
= 0;
517 bool PIOS_BMA180_IRQHandler(void)
520 static const uint8_t pios_bma180_req_buf
[7] = { BMA_X_LSB_ADDR
| 0x80, 0, 0, 0, 0, 0 };
521 uint8_t pios_bma180_dmabuf
[8];
525 // If we can't get the bus then just move on for efficiency
526 if (PIOS_BMA180_ClaimBusISR(&woken
) != 0) {
527 return woken
; // Something else is using bus, miss this data
530 PIOS_SPI_TransferBlock(dev
->spi_id
, pios_bma180_req_buf
, (uint8_t *)pios_bma180_dmabuf
,
531 sizeof(pios_bma180_dmabuf
), NULL
);
533 // TODO: Make this conversion depend on configuration scale
534 struct pios_bma180_data data
;
536 // Don't release bus till data has copied
537 PIOS_BMA180_ReleaseBusISR(&woken
);
539 // Must not return before releasing bus
540 if (fifoBuf_getFree(&dev
->fifo
) < sizeof(data
)) {
544 // Bottom two bits indicate new data and are constant zeros. Don't right
545 // shift because it drops sign bit
546 data
.x
= ((pios_bma180_dmabuf
[2] << 8) | pios_bma180_dmabuf
[1]);
547 data
.y
= ((pios_bma180_dmabuf
[4] << 8) | pios_bma180_dmabuf
[3]);
548 data
.z
= ((pios_bma180_dmabuf
[6] << 8) | pios_bma180_dmabuf
[5]);
552 data
.temperature
= pios_bma180_dmabuf
[7];
554 fifoBuf_putData(&dev
->fifo
, (uint8_t *)&data
, sizeof(data
));
559 #endif /* PIOS_INCLUDE_BMA180 */