Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
ak8975.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 Xavier Paris, Gautier Hattenberger
3  *
4  * This file is part of paparazzi.
5  *
6  * paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
28 #include "peripherals/ak8975.h"
29 #include "mcu_periph/sys_time.h"
30 
31 #define AK8975_MEAS_TIME_MS 9
32 
33 // Internal calibration coeff
34 // Currently fetched at startup but not used after
35 // Only relying on general IMU mag calibration
36 static float calibration_values[3] = { 0, 0, 0 };
37 
38 static float __attribute__((unused)) get_ajusted_value(const int16_t val, const uint8_t axis)
39 {
40  const float H = (float) val;
41  const float corr_factor = calibration_values[axis];
42  const float Hadj = corr_factor * H;
43 
44  return Hadj;
45 }
46 
47 void ak8975_init(struct Ak8975 *ak, struct i2c_periph *i2c_p, uint8_t addr)
48 {
49  /* set i2c_peripheral */
50  ak->i2c_p = i2c_p;
51  /* set i2c address */
52  ak->i2c_trans.slave_addr = addr;
53 
55 
56  ak->initialized = false;
57  ak->status = AK_STATUS_IDLE;
59  ak->data_available = false;
60 }
61 
62 // Configure
63 void ak8975_configure(struct Ak8975 *ak)
64 {
65  // Only configure when not busy
67  && ak->i2c_trans.status != I2CTransDone) {
68  return;
69  }
70 
71  // Only when succesfull continue with next
72  if (ak->i2c_trans.status == I2CTransSuccess) {
73  ak->init_status++;
74  }
75 
77  switch (ak->init_status) {
78 
79  case AK_CONF_UNINIT:
80  // Set AK8975 in fuse ROM access mode to read ADC calibration data
83  i2c_transmit(ak->i2c_p, &(ak->i2c_trans), ak->i2c_trans.slave_addr, 2);
84  break;
85 
86  case AK_REQ_CALIBRATION:
87  // Request AK8975 for ADC calibration data
89  i2c_transceive(ak->i2c_p, &(ak->i2c_trans), ak->i2c_trans.slave_addr, 1, 3);
90  break;
91 
93  // Read config
94  for (uint8_t i =0; i<=2; i++)
96  ((((float)(ak->i2c_trans.buf[i]) - 128.0f)*0.5f)/128.0f)+1.0f;
97 
98  // Set AK8975 in power-down mode to stop read calibration data
101  i2c_transmit(ak->i2c_p, &(ak->i2c_trans), ak->i2c_trans.slave_addr, 2);
102  break;
103 
104  case AK_CONF_REQUESTED:
105  ak->initialized = true;
106  break;
107 
108  default:
109  break;
110  }
111 }
112 
113 void ak8975_read(struct Ak8975 *ak)
114 {
115  if (ak->status != AK_STATUS_IDLE) {
116  return;
117  }
118 
119  // Send single measurement request
122  i2c_transmit(ak->i2c_p, &(ak->i2c_trans), ak->i2c_trans.slave_addr, 2);
124  ak->status = AK_STATUS_MEAS;
125 }
126 
127 // Get raw value
128 #define RawFromBuf(_buf,_idx) ((int16_t)(_buf[_idx] | (_buf[_idx+1] << 8)))
129 // Raw is actually a 14 bits signed value
130 #define Int16FromRaw(_raw) ( (_raw & 0x1FFF) > 0xFFF ? (_raw & 0x1FFF) - 0x2000 : (_raw & 0x0FFF) )
131 void ak8975_event(struct Ak8975 *ak)
132 {
133  if (!ak->initialized) {
134  return;
135  }
136 
137  switch (ak->status) {
138 
139  case AK_STATUS_MEAS:
140  // Send a read data command if measurement time is done (9ms max)
141  if (ak->i2c_trans.status == I2CTransSuccess &&
144  i2c_transceive(ak->i2c_p, &(ak->i2c_trans), ak->i2c_trans.slave_addr, 1, 8);
145  ak->status++;
146  }
147  break;
148 
149  case AK_STATUS_READ:
150  if (ak->i2c_trans.status == I2CTransSuccess) {
151  // Mag data :
152  // Status 1
153  // 1 byte
154  // Measures :
155  // 2 bytes
156  // 2 bytes
157  // 2 bytes
158  // Status 2
159  // 1 byte
160 
161  // Read status and error bytes
162  const bool dr = ak->i2c_trans.buf[0] & 0x01; // data ready
163  const bool de = ak->i2c_trans.buf[7] & 0x04; // data error
164  const bool mo = ak->i2c_trans.buf[7] & 0x08; // mag overflow
165  if (de || !dr) {
166  // read error or data not ready, keep reading
167  break;
168  }
169  if (mo) {
170  // overflow, back to idle
171  ak->status = AK_STATUS_IDLE;
172  }
173  // Copy the data
174  int16_t val;
175  val = RawFromBuf(ak->i2c_trans.buf, 1);
176  ak->data.vect.x = Int16FromRaw(val);
177  val = RawFromBuf(ak->i2c_trans.buf, 3);
178  ak->data.vect.y = Int16FromRaw(val);
179  val = RawFromBuf(ak->i2c_trans.buf, 5);
180  ak->data.vect.z = Int16FromRaw(val);
181  ak->data_available = true;
182  // End reading, back to idle
183  ak->status = AK_STATUS_IDLE;
184  break;
185  }
186  break;
187 
188  default:
190  // Goto idle
192  ak->status = AK_STATUS_IDLE;
193  }
194  break;
195  }
196 }
197 
@ AK_STATUS_IDLE
Definition: ak8963.h:47
@ AK_STATUS_READ
Definition: ak8963.h:48
@ AK_CONF_UNINIT
Definition: ak8963.h:40
void ak8975_read(struct Ak8975 *ak)
Definition: ak8975.c:113
void ak8975_configure(struct Ak8975 *ak)
Definition: ak8975.c:63
void ak8975_init(struct Ak8975 *ak, struct i2c_periph *i2c_p, uint8_t addr)
Definition: ak8975.c:47
#define RawFromBuf(_buf, _idx)
Definition: ak8975.c:128
#define Int16FromRaw(_raw)
Definition: ak8975.c:130
void ak8975_event(struct Ak8975 *ak)
Definition: ak8975.c:131
#define AK8975_MEAS_TIME_MS
Definition: ak8975.c:31
static float calibration_values[3]
Definition: ak8975.c:36
static float get_ajusted_value(const int16_t val, const uint8_t axis)
Definition: ak8975.c:38
Driver for the AKM AK8975 magnetometer.
enum Ak8975Status status
main status
Definition: ak8975.h:64
#define AK8975_MODE_FUSE_ACCESS
Definition: ak8975.h:39
@ AK_DISABLE_ACCESS_CALIBRATION
Definition: ak8975.h:47
@ AK_CONF_REQUESTED
Definition: ak8975.h:48
@ AK_REQ_CALIBRATION
Definition: ak8975.h:46
struct i2c_transaction i2c_trans
i2c transaction used for communication with the ak8936
Definition: ak8975.h:61
enum Ak8975ConfStatus init_status
init status
Definition: ak8975.h:65
uint32_t last_meas_time
last measurement time in ms
Definition: ak8975.h:66
@ AK_STATUS_MEAS
Definition: ak8975.h:54
#define AK8975_REG_CNTL_ADDR
Definition: ak8975.h:37
volatile bool data_available
data ready flag
Definition: ak8975.h:68
bool initialized
config done flag
Definition: ak8975.h:62
struct i2c_periph * i2c_p
peripheral used for communcation
Definition: ak8975.h:60
#define AK8975_MODE_SINGLE_MEAS
Definition: ak8975.h:41
#define AK8975_REG_ASASX
Definition: ak8975.h:38
union Ak8975::@311 data
#define AK8975_REG_ST1_ADDR
Definition: ak8975.h:36
#define AK8975_MODE_POWER_DOWN
Definition: ak8975.h:40
Definition: ak8975.h:59
uint32_t get_sys_time_msec(void)
Get the time in milliseconds since startup.
Definition: sys_time_arch.c:98
volatile uint8_t buf[I2C_BUF_LEN]
Transaction buffer With I2C_BUF_LEN number of bytes.
Definition: i2c.h:122
enum I2CTransactionStatus status
Transaction status.
Definition: i2c.h:126
uint8_t slave_addr
Slave address.
Definition: i2c.h:104
bool i2c_transmit(struct i2c_periph *p, struct i2c_transaction *t, uint8_t s_addr, uint8_t len)
Submit a write only transaction.
Definition: i2c.c:324
bool i2c_transceive(struct i2c_periph *p, struct i2c_transaction *t, uint8_t s_addr, uint8_t len_w, uint16_t len_r)
Submit a write/read transaction.
Definition: i2c.c:344
@ I2CTransSuccess
transaction successfully finished by I2C driver
Definition: i2c.h:57
@ I2CTransFailed
transaction failed
Definition: i2c.h:58
@ I2CTransDone
transaction set to done by user level
Definition: i2c.h:59
static struct FloatVect3 H
Architecture independent timing functions.
uint16_t val[TCOUPLE_NB]
short int16_t
Typedef defining 16 bit short type.
Definition: vl53l1_types.h:93
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98