summaryrefslogtreecommitdiff
path: root/fw/mpu6050.c
diff options
context:
space:
mode:
authorjaseg <git@jaseg.net>2020-10-11 23:31:12 +0200
committerjaseg <git@jaseg.net>2020-10-11 23:31:12 +0200
commit226fef1618dd9a37c050bb79a24c77396cd14c46 (patch)
treeed1d41cd5268e607ecd2abe8e628a1e796fda838 /fw/mpu6050.c
parent0e25682ed73ead8da26ea8659492bd5bce3cfe64 (diff)
downloadusb-remote-226fef1618dd9a37c050bb79a24c77396cd14c46.tar.gz
usb-remote-226fef1618dd9a37c050bb79a24c77396cd14c46.tar.bz2
usb-remote-226fef1618dd9a37c050bb79a24c77396cd14c46.zip
Initial fw commit
Diffstat (limited to 'fw/mpu6050.c')
-rw-r--r--fw/mpu6050.c244
1 files changed, 244 insertions, 0 deletions
diff --git a/fw/mpu6050.c b/fw/mpu6050.c
new file mode 100644
index 0000000..dc374d8
--- /dev/null
+++ b/fw/mpu6050.c
@@ -0,0 +1,244 @@
+/* MPU6050 device I2C library code for ARM STM32F103xx is placed under the MIT license
+ Copyright (c) 2012 Harinadha Reddy Chintalapalli
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "mpu6050.h"
+#include "i2c.h"
+
+/** @defgroup MPU_Library
+ * @{
+ */
+
+/** Power on and prepare for general usage.
+ * This will activate the device and take it out of sleep mode (which must be done
+ * after start-up). This function also sets both the accelerometer and the gyroscope
+ * to their most sensitive settings, namely +/- 2g and +/- 250 degrees/sec, and sets
+ * the clock source to use the X Gyro for reference, which is slightly better than
+ * the default internal clock source.
+ */
+void mpu_init()
+{
+ mpu_reg_write(MPU_RA_PWR_MGMT1, MPU_CLOCK_PLL_XGYRO);
+ mpu_set_gyro_fs(MPU_GYRO_FS_250);
+ mpu_set_accel_fs(MPU_ACCEL_FS_2);
+}
+
+void mpu_init_low_power(uint8_t wake_freq, bool enable_interrupt)
+{
+ mpu_set_gyro_fs(MPU_GYRO_FS_250);
+ mpu_set_accel_fs(MPU_ACCEL_FS_2);
+ /* For these two regs, see pwr mgmt reg 2 desc in reg map ref manual, pg. 42 */
+ mpu_reg_write(MPU_RA_PWR_MGMT1, MPU_PWR_MGMT1_CYCLE | MPU_PWR_MGMT1_TEMP_DIS | MPU_CLOCK_INTERNAL);
+ mpu_reg_write(MPU_RA_PWR_MGMT2, MPU_PWR_MGMT2_STBY_XG | MPU_PWR_MGMT2_STBY_YG | MPU_PWR_MGMT2_STBY_ZG | wake_freq);
+
+ if (enable_interrupt) {
+ mpu_reg_write(MPU_RA_INT_PIN_CFG, MPU_INT_PIN_CFG_RD_CLEAR);
+ mpu_reg_write(MPU_RA_INT_ENABLE, MPU_INT_ENABLE_DATA_RDY);
+ }
+}
+
+/** Verify the I2C connection.
+ * Make sure the device is connected and responds as expected.
+ * @return True if connection is valid, FALSE otherwise
+ */
+bool mpu_test_connection()
+{
+ return mpu_device_id() == MPU_DEVICE_ID;
+}
+
+/** Get Device ID.
+ * This register is used to verify the identity of the device (0b110100).
+ * @return Device ID (should be 0x68, 104 dec, 150 oct)
+ * @see MPU_RA_WHO_AM_I
+ * @see MPU_WHO_AM_I_BIT
+ * @see MPU_WHO_AM_I_LENGTH
+ */
+uint8_t mpu_device_id()
+{
+ return mpu_reg_read(MPU_RA_WHO_AM_I) >> MPU_WHO_AM_I_Pos;
+}
+
+/** Set full-scale gyroscope range.
+ * @param range New full-scale gyroscope range value
+ * @see MPU_GetFullScaleGyroRange()
+ * @see MPU_GYRO_FS_250
+ * @see MPU_RA_GYRO_CONFIG
+ * @see MPU_GCONFIG_FS_SEL_BIT
+ * @see MPU_GCONFIG_FS_SEL_LENGTH
+ */
+void mpu_set_gyro_fs(uint8_t range)
+{
+ mpu_reg_write(MPU_RA_GYRO_CONFIG, range);
+}
+
+
+/** Get full-scale gyroscope range.
+ * The FS_SEL parameter allows setting the full-scale range of the gyro sensors,
+ * as described in the table below.
+ *
+ * <pre>
+ * 0 = +/- 250 degrees/sec
+ * 1 = +/- 500 degrees/sec
+ * 2 = +/- 1000 degrees/sec
+ * 3 = +/- 2000 degrees/sec
+ * </pre>
+ *
+ * @return Current full-scale gyroscope range setting
+ * @see MPU_GYRO_FS_250
+ * @see MPU_RA_GYRO_CONFIG
+ * @see MPU_GCONFIG_FS_SEL_BIT
+ * @see MPU_GCONFIG_FS_SEL_LENGTH
+ */
+uint8_t mpu_get_gyro_fs()
+{
+ return mpu_reg_read(MPU_RA_GYRO_CONFIG) & MPU_GYRO_FS_SEL_Msk;
+}
+
+/** Get full-scale accelerometer range.
+ * The FS_SEL parameter allows setting the full-scale range of the accelerometer
+ * sensors, as described in the table below.
+ *
+ * <pre>
+ * 0 = +/- 2g
+ * 1 = +/- 4g
+ * 2 = +/- 8g
+ * 3 = +/- 16g
+ * </pre>
+ *
+ * @return Current full-scale accelerometer range setting
+ * @see MPU_ACCEL_FS_2
+ * @see MPU_RA_ACCEL_CONFIG
+ */
+uint8_t mpu_get_accel_fs()
+{
+ return mpu_reg_read(MPU_RA_ACCEL_CONFIG) & MPU_ACCEL_CONFIG_FS_SEL_Msk;
+}
+
+/** Set full-scale accelerometer range.
+ * @param range New full-scale accelerometer range setting
+ * @see MPU_GetFullScaleAccelRange()
+ */
+void mpu_set_accel_fs(uint8_t range)
+{
+ mpu_reg_write(MPU_RA_ACCEL_CONFIG, range);
+}
+
+/** Get sleep mode status.
+ * Setting the SLEEP bit in the register puts the device into very low power
+ * sleep mode. In this mode, only the serial interface and internal registers
+ * remain active, allowing for a very low standby current. Clearing this bit
+ * puts the device back into normal mode. To save power, the individual standby
+ * selections for each of the gyros should be used if any gyro axis is not used
+ * by the application.
+ * @return Current sleep mode bit
+ * @see MPU_RA_PWR_MGMT_1
+ * @see MPU_PWR1_SLEEP_BIT
+ */
+bool mpu_get_sleep_mode()
+{
+ return mpu_reg_read(MPU_RA_PWR_MGMT1) & MPU_PWR_MGMT1_SLEEP;
+}
+
+/** Set sleep mode status.
+ * @param enabled New sleep mode enabled status
+ * @see MPU_GetSleepModeStatus()
+ * @see MPU_RA_PWR_MGMT_1
+ * @see MPU_PWR1_SLEEP_BIT
+ */
+void mpu_set_sleep_mode(bool val)
+{
+ int tmp = mpu_reg_read(MPU_RA_PWR_MGMT1);
+ tmp = (tmp & ~MPU_PWR_MGMT1_SLEEP) | (val ? MPU_PWR_MGMT1_SLEEP : 0);
+ mpu_reg_write(MPU_RA_PWR_MGMT1, tmp);
+}
+
+/** Get raw 6-axis motion sensor readings (accel/gyro).
+ * Retrieves all currently available motion sensor values.
+ * @see MPU_RA_ACCEL_XOUT_H
+ */
+void mpu_read_accel_gyro(struct mpu_raw_data *out)
+{
+ struct mpu_raw_data buf;
+ mpu_reg_read_multiple(MPU_RA_ACCEL_XOUT_H, (uint8_t *)&buf, sizeof(buf));
+
+ for (uint8_t i=0; i<ARRAY_SIZE(buf.channels); i++)
+ out->channels[i] = (int16_t)be16toh((uint16_t)buf.channels[i]);
+}
+
+int16_t mpu_read_temp() {
+ uint16_t buf;
+ mpu_reg_read_multiple(MPU_RA_TEMP_OUT_H, (uint8_t *)&buf, sizeof(buf));
+ return (int16_t)be16toh(buf);
+}
+
+void mpu_read_accel(struct mpu_accel_data *out)
+{
+ struct mpu_accel_data buf;
+ mpu_reg_read_multiple(MPU_RA_ACCEL_XOUT_H, (uint8_t *)&buf, sizeof(buf));
+
+ for (uint8_t i=0; i<ARRAY_SIZE(buf.channels); i++)
+ out->channels[i] = (int16_t)be16toh((uint16_t)buf.channels[i]);
+}
+
+void mpu_read_gyro(struct mpu_gyro_data *out)
+{
+ struct mpu_gyro_data buf;
+ mpu_reg_read_multiple(MPU_RA_GYRO_XOUT_H, (uint8_t *)&buf, sizeof(buf));
+
+ for (uint8_t i=0; i<ARRAY_SIZE(buf.channels); i++)
+ out->channels[i] = (int16_t)be16toh((uint16_t)buf.channels[i]);
+}
+
+/**
+ * @brief Writes one byte to the MPU6050.
+ * @param reg : address of the register in which the data will be written
+ * @param val : the data to be written to the MPU6050.
+ * @return None
+ */
+void mpu_reg_write(uint8_t reg, uint8_t val)
+{
+ uint8_t tx[2] = {reg, val};
+ i2c_transmit(MPU_I2C_PERIPH, MPU_DEFAULT_ADDRESS, tx, sizeof(tx), I2C_GENSTOP_YES);
+}
+
+/**
+ * @brief Reads a block of data from the MPU6050.
+ * @param buf : pointer to the buffer that receives the data read from the MPU6050.
+ * @param addr : MPU6050's internal address to read from.
+ * @param len : number of bytes to read from the MPU6050
+ * @return None
+ */
+void mpu_reg_read_multiple(uint8_t addr, uint8_t* buf, size_t len)
+{
+ i2c_transmit(MPU_I2C_PERIPH, MPU_DEFAULT_ADDRESS, &addr, 1, I2C_GENSTOP_NO);
+ i2c_receive(MPU_I2C_PERIPH, MPU_DEFAULT_ADDRESS, buf, len);
+}
+
+uint8_t mpu_reg_read(uint8_t addr)
+{
+ uint8_t buf;
+ i2c_transmit(MPU_I2C_PERIPH, MPU_DEFAULT_ADDRESS, &addr, 1, I2C_GENSTOP_NO);
+ i2c_receive(MPU_I2C_PERIPH, MPU_DEFAULT_ADDRESS, &buf, 1);
+ return buf;
+}
+/**
+ * @}
+ *//* end of group MPU_Library */