22#include <linux/spi/spidev.h>
34 jevois::
IMU(), itsDevName(devname), itsFd(-1), itsIMUbank(0)
39 unsigned int speed = 7000000;
45 itsFd = open(devname.c_str(), O_RDWR);
46 if (
itsFd < 0)
LFATAL(
"Error opening IMU SPI device " << devname);
48 unsigned char mode = SPI_CPOL | SPI_CPHA;
51 unsigned char bits = 8;
63 writeRegister(ICM20948_REG_USER_CTRL, ICM20948_BIT_I2C_IF_DIS | ICM20948_BIT_DMP_RST |
64 ICM20948_BIT_DIAMOND_DMP_RST);
68 if (ret == ICM20948_DEVICE_ID)
LINFO(
"Detected ICM20948 IMU on " << devname <<
" @ " << speed <<
"Hz");
69 else LFATAL(
"Failed to detect ICM20948 on " << devname <<
" @ " << speed <<
"Hz: device ID=0x" << std::hex <<
70 ret <<
", should be 0x" << ICM20948_DEVICE_ID);
73 writeRegister(ICM20948_REG_USER_CTRL, ICM20948_BIT_I2C_IF_DIS | ICM20948_BIT_I2C_MST_EN | ICM20948_BIT_FIFO_EN);
80 writeRegister(ICM20948_REG_USER_CTRL, ICM20948_BIT_I2C_IF_DIS | ICM20948_BIT_I2C_MST_EN | ICM20948_BIT_FIFO_EN |
93 LERROR(
"Giving up trying to setup ICM20948 IMU with DMP -- DMP NOT OPERATIONAL, BASIC IMU MAY WORK OR NOT");
99 if (itsFd >= 0) close(itsFd);
108 unsigned char const * dataout)
110 unsigned char dreg = (reg & 0x7f) | dir;
111 unsigned int speed = 7000000;
113 struct spi_ioc_transfer xfer[2] =
116 .tx_buf = (
unsigned long)&dreg,
125 .word_delay_usecs = 0,
129 .tx_buf = (
unsigned long)dataout,
130 .rx_buf = (
unsigned long)datain,
131 .len =
static_cast<unsigned int>(siz),
138 .word_delay_usecs = 0,
143 XIOCTL(itsFd, SPI_IOC_MESSAGE(2), xfer);
149 uint8_t
const bank = (reg >> 7) & 0x03;
150 if (itsIMUbank == bank)
return;
152 uint8_t dataout = uint8_t(bank << 4);
153 LDEBUG(
"Writing 0x" << std::hex << dataout <<
" to 0x" << ICM20948_REG_BANK_SEL);
161 LDEBUG(
"Writing 0x" << std::hex << val <<
" to 0x" << reg);
162 selectBank(reg);
unsigned char gogo;
171 case ICM20948_REG_I2C_MST_CTRL:
172 case ICM20948_REG_I2C_SLV4_CTRL:
173 case ICM20948_REG_TEMP_CONFIG:
175 case ICM20948_REG_MEM_START_ADDR:
176 case ICM20948_REG_MEM_R_W:
177 case ICM20948_REG_MEM_BANK_SEL:
179 case ICM20948_REG_USER_CTRL:
180 case ICM20948_REG_PWR_MGMT_1:
181 case ICM20948_REG_PWR_MGMT_2:
187 if (delay) std::this_thread::sleep_for(std::chrono::milliseconds(5));
191 unsigned char ret = readRegister(reg);
194 LERROR(
"Read back reg 0x"<<std::hex<<reg<<
" returned 0x"<<ret<<
" instead of 0x"<<val);
199 if (delay) std::this_thread::sleep_for(std::chrono::milliseconds(5));
201 ret = readRegister(reg);
203 LERROR(
"RETRY Read back reg 0x"<<std::hex<<reg<<
" returned 0x"<<ret<<
" instead of 0x"<<val);
205 LERROR(
"RETRY Read back reg 0x"<<std::hex<<reg<<
" returned 0x"<<ret<<
" -- OK");
214 unsigned char datain;
unsigned char gogo = 0;
216 LDEBUG(
"Register 0x" << std::hex << reg <<
" has value 0x" << datain);
223 if (num > 256)
LFATAL(
"Maximum allowed size 256 bytes. You must break down larger transfers into 256 byte chunks.");
224 LDEBUG(
"Writing " << num <<
" values to 0x"<< std::hex << reg);
232 if (num > 256)
LFATAL(
"Maximum allowed size 256 bytes. You must break down larger transfers into 256 byte chunks.");
235 LDEBUG(
"Received " << num <<
" values from register 0x" << std::hex << reg);
#define ICM20948_SPI_WRITE
#define ICM20948_SPI_READ
Abstract interface to an ICM20948 inertial measurement unit (IMU)
void loadDMPfirmware(bool verify=false, bool errthrow=false)
Load the DMP firmware.
void writeRegisterArray(unsigned short reg, unsigned char const *vals, size_t num) override
Write an array of values to the camera's IMU registers.
void writeRegister(unsigned short reg, unsigned char val) override
Write a value to one of the IMU registers.
virtual ~IMUspi()
Destructor.
virtual bool isSPI() const override
Returns true if we use SPI for transfers. Used when ICM20948_REG_USER_CTRL is written to.
unsigned char readRegister(unsigned short reg) override
Read a value from one of the camera's IMU registers.
void selectBank(unsigned short reg)
IMUspi(std::string const &devname)
Constructor.
void readRegisterArray(unsigned short reg, unsigned char *vals, size_t num) override
Read an array of values from the camera's IMU registers.
void spi_xfer(unsigned char addr, unsigned char dir, size_t siz, unsigned char *datain, unsigned char const *dataout)
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level.
#define LDEBUG(msg)
Convenience macro for users to print out console or syslog messages, DEBUG level.
#define LERROR(msg)
Convenience macro for users to print out console or syslog messages, ERROR level.
#define LINFO(msg)
Convenience macro for users to print out console or syslog messages, INFO level.
#define XIOCTL(dev, req, mem)
Helper macro to execute an ioctl, ignore interruptions, and, if error, issue a fatal message and thro...
Main namespace for all JeVois classes and functions.