Skip to content

Commit

Permalink
Implement MMA7660 accelerometer driver
Browse files Browse the repository at this point in the history
  • Loading branch information
twasilczyk committed Sep 7, 2021
1 parent 64ce36f commit 0050e2c
Show file tree
Hide file tree
Showing 8 changed files with 248 additions and 1 deletion.
20 changes: 19 additions & 1 deletion examples/srxe/display/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
// ----------------------------------------------------------------------------

#include <modm/board.hpp>
//#include <modm/architecture/interface/i2c_master.hpp>

#include <modm/driver/inertial/mma7660.hpp>

modm::Mma7660<Board::i2c::I2cMaster, GpioE5> accel;

int
main()
Expand All @@ -20,8 +25,21 @@ main()

display.setCursor(115, 54);
display.setFont(modm::font::Ubuntu_36);
display << "Hello World";
display << "Hello World\n";
display.drawRoundedRectangle({100, 48}, 184, 40, 10);

display << "i";
display << 1;
bool ok = RF_CALL_BLOCKING(accel.ping());
display << (ok ? "OK" : "ERR");
accel.initialize();
display << 2;

display.update();
while (true) {
display.setCursor(0, 20);
const auto r = RF_CALL_BLOCKING(accel.read());
display << "x=" << r.x << " y=" << r.y << " z=" << r.z << " ";
display.update();
}
}
2 changes: 2 additions & 0 deletions examples/srxe/display/project.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@
</options>
<modules>
<module>modm:build:scons</module>
<module>modm:architecture:i2c.device</module>
<module>modm:driver:mma7660</module>
</modules>
</library>
9 changes: 9 additions & 0 deletions src/modm/board/srxe/board.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ using SpiMaster = modm::platform::SpiMaster;

} // namespace spi

namespace i2c {

using I2cMaster = modm::platform::I2cMaster;

} // namespace i2c

namespace DisplayGpio {

using DC = GpioD6;
Expand All @@ -62,6 +68,9 @@ initialize() {
// Clock is high when inactive, data is sampled on clock trailing edge.
spi::SpiMaster::setDataMode(spi::SpiMaster::DataMode::Mode3);

i2c::I2cMaster::connect<GpioD0::Scl, GpioD1::Sda>(i2c::I2cMaster::PullUps::Internal);
i2c::I2cMaster::initialize<SystemClock, 100_kHz>(); // max 400kHz

enableInterrupts();

display.initialize();
Expand Down
1 change: 1 addition & 0 deletions src/modm/board/srxe/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def prepare(module, options):
":platform:clock",
":platform:core",
":platform:gpio",
":platform:i2c",
":platform:spi",
":platform:uart:0",
":driver:st7586s")
Expand Down
58 changes: 58 additions & 0 deletions src/modm/driver/inertial/mma7660.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2021, Tomasz Wasilczyk
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#pragma once

#include "mma7660_register.hpp"

#include <modm/architecture/interface/i2c_device.hpp>
//TODO #include <modm/processing/protothread.hpp>
#include <modm/math/utils.hpp>

namespace modm
{

// TODO: inside class
struct Mma7660Val {
uint8_t x, y, z;
};

template <typename I2cMaster, typename INT>
class Mma7660 : public modm::I2cDevice<I2cMaster, 3> {
using Register = detail::mma7660::Register;

static constexpr uint8_t address = 0x4C;

uint8_t buffer[2];

modm::ResumableResult<void>
writeRead(Register reg, const void* writeBuffer, uint8_t writeLen, uint8_t readLen);

template <typename T>
modm::ResumableResult<void>
write(Register reg, T data);

template <typename T>
modm::ResumableResult<T>
read(Register reg);

public:
Mma7660();

void initialize();

modm::ResumableResult<Mma7660Val>
read();
};

} // namespace modm

#include "mma7660_impl.hpp"
31 changes: 31 additions & 0 deletions src/modm/driver/inertial/mma7660.lb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2021, Tomasz Wasilczyk
#
# This file is part of the modm project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# -----------------------------------------------------------------------------


def init(module):
module.name = ":driver:mma7660"
module.description = """
# MMA7660 3-Axis Orientation/Motion Detection Sensor
"""

def prepare(module, options):
module.depends(
":architecture:i2c.device",
":architecture:register",
":math:utils")
return True

def build(env):
env.outbasepath = "modm/src/modm/driver/inertial"
env.copy("mma7660.hpp")
env.copy("mma7660_impl.hpp")
env.copy("mma7660_register.hpp")
81 changes: 81 additions & 0 deletions src/modm/driver/inertial/mma7660_impl.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2021, Tomasz Wasilczyk
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#pragma once
#include "mma7660.hpp"

#include <cstring>

namespace modm
{

template <typename I2cMaster, typename INT>
Mma7660<I2cMaster, INT>::Mma7660() : modm::I2cDevice<I2cMaster, 3>(address) {}

template <typename I2cMaster, typename INT>
modm::ResumableResult<void>
Mma7660<I2cMaster, INT>::writeRead(Register reg, const void* writeBuffer, uint8_t writeLen, uint8_t readLen) {
RF_BEGIN();
static_assert(sizeof(buffer[0]) == sizeof(reg));
buffer[0] = static_cast<uint8_t>(reg);
memcpy(&buffer[1], writeBuffer, writeLen);

this->transaction.configureWriteRead(buffer, writeLen + 1, buffer, readLen);
bool ok; // TODO: ?
ok = RF_CALL(this->runTransaction());
modm_assert(ok, "mma7660.rt", "I2C transaction failed", reg);

RF_END();
}

template <typename I2cMaster, typename INT>
template <typename T>
modm::ResumableResult<void>
Mma7660<I2cMaster, INT>::write(Register reg, T data) {
static_assert(sizeof(T) + sizeof(reg) <= sizeof(buffer));
RF_BEGIN();
RF_END_RETURN_CALL(writeRead(reg, &data, sizeof(data), 0));
}

template <typename I2cMaster, typename INT>
template <typename T>
modm::ResumableResult<T>
Mma7660<I2cMaster, INT>::read(Register reg) {
static_assert(sizeof(T) <= sizeof(buffer));
RF_BEGIN();
RF_CALL(writeRead(reg, nullptr, 0, sizeof(T)));
RF_END_RETURN(*reinterpret_cast<T*>(buffer));
}

template <typename I2cMaster, typename INT>
void Mma7660<I2cMaster, INT>::initialize() {
using namespace modm::detail::mma7660;

INT::setInput(modm::platform::Gpio::InputType::PullUp);

RF_CALL_BLOCKING(write(Register::Mode, registers::Mode_t(registers::Mode::ActiveMode)));
}

template <typename I2cMaster, typename INT>
modm::ResumableResult<Mma7660Val>
Mma7660<I2cMaster, INT>::read() {
RF_BEGIN();
static Mma7660Val val;
val = {};
// TODO: read all at once
// TODO: check alert field
val.x = RF_CALL(read<uint8_t>(Register::XOut));
val.y = RF_CALL(read<uint8_t>(Register::YOut));
val.z = RF_CALL(read<uint8_t>(Register::ZOut));
RF_END_RETURN(val);
}

} // namespace modm
47 changes: 47 additions & 0 deletions src/modm/driver/inertial/mma7660_register.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2021, Tomasz Wasilczyk
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#pragma once

namespace modm::detail::mma7660
{

enum class Register : uint8_t {
XOut = 0x00, ///< X output (read only except in Test Mode).
YOut = 0x01, ///< Y output (read only except in Test Mode).
ZOut = 0x02, ///< Z output (read only except in Test Mode).
Tilt = 0x03, ///< Tilt status (read only).
SampleRateStatus = 0x04, ///< Sample rate status (read only).
SleepCount = 0x05, ///< Sleep count (read/write).
IntSetup = 0x06, ///< Interrupt setup.
Mode = 0x07, ///< Mode (read/write).
SampleRate = 0x08, ///< Sample rate (read/write).
TapDetection = 0x09, ///< Tap/pulse detection (read/write).
TapDebounceCount = 0x0A, ///< Tap/pulse debounce count (read/write).
};

namespace registers {

enum class Mode : uint8_t {
ActiveMode = Bit0,
TestMode = Bit2,
AutoWake = Bit3,
AutoSleep = Bit4,
SleepCounterPrescaler = Bit5, ///< Sleep counter clock is divided by 16.
IntPushPull = Bit6, ///< If set, INT is push-pull. If not, it's open-drain.
IntActiveHigh = Bit7, ///< If set, INT is active high.
};
typedef modm::Flags8<Mode> Mode_t;
MODM_TYPE_FLAGS(Mode_t);

} // namespace registers

} // namespace modm::detail::mma7660

0 comments on commit 0050e2c

Please sign in to comment.