I write a basic container class encapsulates some other classes, to read my GY89 sensor via I2C. Unfortunately, I just stumbled with a black magic kind of situation.
The code is like below,
GY89.ino
#include "GY89.h"
GY89 sensor;
void setup()
{
Serial.begin(112500);
Serial.println("begin 112500");
}
void loop()
{
sensor.print_all();
delay(100);
}
GY89.h
#pragma once
#include <Arduino.h>
#include "L3GD20.hpp"
class GY89 {
private:
L3GD20 *gyro;
public:
GY89() {
gyro = new L3GD20;
}
~GY89() {
delete gyro;
void print_all() {
gyro->read();
Serial.print(gyro->temperature);
Serial.print(",");
Serial.print(gyro->rate.x);
Serial.print(",");
Serial.print(gyro->rate.y);
Serial.print(",");
Serial.print(gyro->rate.z);
}
};
If I upload this code, Mega R3 board gets stuck, cannot print/read from serial nor can update digital pins. But if change the third line in GY89.ino to GY89 *sensor; everything starts to work again.
There is no compilation errors, but board kills itself, only the GND and Vdd pins work. Hell, I'm confused...
EDIT:
The same issue happens if I directly create L3GD20 class instance, I could have made a mistake while writing the driver, code as follows.
GY89.ino
[code]#include "GY89.h"
L3GD20 gyro;
void setup()
{
Serial.begin(112500);
Serial.println("print something!!!");
}
void loop()
{
Serial.println("just nothing...");
}
[/code]
Like if I change it to L3GD20 *gyro;, it works...
L3GD20.hpp
#pragma once
#include <Arduino.h>
#include <Wire.h>
class L3GD20 {
public:
enum REG_ADDR {
WHO_AM_I = 0x0F,
CTRL_REG1 = 0x20,
CTRL_REG2 = 0x21,
CTRL_REG3 = 0x22,
CTRL_REG4 = 0x23,
CTRL_REG5 = 0x24,
REFERENCE = 0x25,
OUT_TEMP = 0x26,
STATUS_REG = 0x27,
OUT_X_L = 0x28,
OUT_X_H = 0x29,
OUT_Y_L = 0x2A,
OUT_Y_H = 0x2B,
OUT_Z_L = 0x2C,
OUT_Z_H = 0x2D,
FIFO_CTRL_REG = 0x2E,
FIFO_SRC_REG = 0x2F,
INT1_CFG = 0x30,
INT1_SRC = 0x31,
INT1_THS_XH = 0x32,
INT1_THS_XL = 0x33,
INT1_THS_YH = 0x34,
INT1_THS_YL = 0x35,
INT1_THS_ZH = 0x36,
INT1_THS_ZL = 0x37,
INT1_DURATION = 0x38
};
enum POWER_MODE {
power_down,
power_up,
sleep
};
enum SA0_STATE {
sa0_low,
sa0_high,
sa0_auto
};
enum FS_RATE {
fs250,
fs500,
fs2000
};
enum ODR {
odr95 = 0x00,
odr190 = 0x60,
odr380 = 0x80,
odr760 = 0xC0
};
enum BANDWIDTH {
bw0 = 0x00,
bw1 = 0x10,
bw2 = 0x20,
bw3 = 0x30
};
enum HP_FILTER_MODE {
hp_normal_reset = 0x00,
hp_ref_signal = 0x10,
hp_normal = 0x20,
hp_autoreset = 0x30
};
enum HP_FILTER_CUTOFF {
hp_cof0 = 0x00,
hp_cof1 = 0x01,
hp_cof2 = 0x02,
hp_cof3 = 0x03,
hp_cof4 = 0x04,
hp_cof5 = 0x05,
hp_cof6 = 0x06,
hp_cof7 = 0x07,
hp_cof8 = 0x08,
hp_cof9 = 0x09,
};
typedef struct { int16_t x, y, z; } vector;
vector rate;
uint8_t temperature;
L3GD20();
void read();
void set_power(const POWER_MODE&) const;
void set_bandwidth(const BANDWIDTH&) const;
void set_filter_mode(const HP_FILTER_MODE&, const HP_FILTER_CUTOFF&) const;
void enable_filter(const bool&) const;
explicit operator bool() const { return address; }
private:
uint8_t address;
uint8_t axis_status;
bool find_address();
void write_reg(const REG_ADDR&, const uint8_t&) const;
uint8_t read_reg(const REG_ADDR&) const;
};
L3Gd20.cpp
#include "L3GD20.hpp"
L3GD20::L3GD20()
{
if (!find_address()) {
address = 0;
return;
}
// 95 ODR & 12.5 BW, all axis power on
write_reg(CTRL_REG1, 0x0F);
// Full scale 250
write_reg(CTRL_REG4, 0x20);
}
bool L3GD20::find_address()
{
uint8_t SA0_LO_ADDR = 0x6A;
uint8_t SA0_HI_ADDR = 0x6B;
Wire.beginTransmission(SA0_LO_ADDR);
Wire.write(WHO_AM_I);
if (Wire.endTransmission()) {
Wire.beginTransmission(SA0_HI_ADDR);
Wire.write(WHO_AM_I);
if (Wire.endTransmission()) {
return false;
} else {
address = SA0_HI_ADDR;
}
} else {
address = SA0_LO_ADDR;
}
Wire.requestFrom(address, (byte) 1);
if (Wire.available()) {
Wire.read(); // dump whoami
} else {
return false;
}
return true;
}
uint8_t L3GD20::read_reg(const REG_ADDR ®) const
{
Wire.beginTransmission(address);
Wire.write(reg);
if (!Wire.endTransmission()) {
Wire.requestFrom(address, (byte) 1);
return Wire.read();
}
return 0;
}
void L3GD20::write_reg(const REG_ADDR ®, const uint8_t &val) const
{
Wire.beginTransmission(address);
Wire.write(reg);
Wire.write(val);
Wire.endTransmission();
}
void L3GD20::read()
{
Wire.beginTransmission(address);
Wire.write(OUT_TEMP | (1U << 7));
Wire.endTransmission();
Wire.requestFrom(address, (byte) 8);
temperature = 45 - Wire.read();
axis_status = Wire.read();
uint8_t xl = Wire.read();
uint8_t xh = Wire.read();
uint8_t yl = Wire.read();
uint8_t yh = Wire.read();
uint8_t zl = Wire.read();
uint8_t zh = Wire.read();
// combine high and low bytes
rate.x = (int16_t)((xh << 8U) | xl);
rate.y = (int16_t)((yh << 8U) | yl);
rate.z = (int16_t)((zh << 8U) | zl);
}
void L3GD20::set_power(const POWER_MODE &mode) const
{
uint8_t val = read_reg(CTRL_REG1) & 0xF0;
switch (mode) {
case power_down: val |= 0x00; break;
case sleep: val |= 0x08; break;
default: case power_up: val |= 0x0F; break;
}
write_reg(CTRL_REG1, val);
}
void L3GD20::set_bandwidth(const BANDWIDTH &bw) const
{
write_reg(CTRL_REG1, (read_reg(CTRL_REG1) & 0xCF) | bw);
}
void L3GD20::set_filter_mode(const HP_FILTER_MODE &mode, const HP_FILTER_CUTOFF &cof) const
{
write_reg(CTRL_REG2, (mode | cof) & 0x3F);
}
void L3GD20::enable_filter(const bool &enable) const
{
write_reg(CTRL_REG5, (read_reg(CTRL_REG5) & 0xEF) | (((uint8_t)enable) << 4));
}