Skip to content

Commit 9a36921

Browse files
author
Owen
authored
Mag support for SPI. Implement mag over I2C master rather than ba… (#10)
Mag support for SPI. Implement mag over I2C master rather than bare I2C.
2 parents c5e9ce1 + 7fb94d8 commit 9a36921

File tree

4 files changed

+799
-584
lines changed

4 files changed

+799
-584
lines changed

src/ICM_20948.cpp

Lines changed: 65 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ ICM_20948_AGMT_t ICM_20948::getAGMT(void)
1818
{
1919
status = ICM_20948_get_agmt(&_device, &agmt);
2020

21-
if (_has_magnetometer)
22-
{
23-
getMagnetometerData(&agmt);
24-
}
25-
2621
return agmt;
2722
}
2823

@@ -527,7 +522,6 @@ ICM_20948_Status_e ICM_20948::intEnableRawDataReady(bool enable)
527522
}
528523
if (en.RAW_DATA_0_RDY_EN != enable)
529524
{
530-
Serial.println("mismatch error");
531525
status = ICM_20948_Stat_Err;
532526
return status;
533527
}
@@ -589,6 +583,12 @@ ICM_20948_Status_e ICM_20948::i2cMasterEnable(bool enable)
589583
return status;
590584
}
591585

586+
ICM_20948_Status_e ICM_20948::i2cMasterReset()
587+
{
588+
status = ICM_20948_i2c_master_reset(&_device);
589+
return status;
590+
}
591+
592592
ICM_20948_Status_e ICM_20948::i2cMasterConfigureSlave(uint8_t slave, uint8_t addr, uint8_t reg, uint8_t len, bool Rw, bool enable, bool data_only, bool grp, bool swap)
593593
{
594594
status = ICM_20948_i2c_master_configure_slave(&_device, slave, addr, reg, len, Rw, enable, data_only, grp, swap);
@@ -600,6 +600,7 @@ ICM_20948_Status_e ICM_20948::i2cMasterSLV4Transaction(uint8_t addr, uint8_t reg
600600
status = ICM_20948_i2c_master_slv4_txn(&_device, addr, reg, data, len, Rw, send_reg_addr);
601601
return status;
602602
}
603+
603604
ICM_20948_Status_e ICM_20948::i2cMasterSingleW(uint8_t addr, uint8_t reg, uint8_t data)
604605
{
605606
status = ICM_20948_i2c_master_single_w(&_device, addr, reg, &data);
@@ -684,49 +685,39 @@ ICM_20948_Status_e ICM_20948::startupDefault(void)
684685
status = retval;
685686
return status;
686687
}
687-
688-
_has_magnetometer = true;
689688
retval = startupMagnetometer();
690-
if ((retval != ICM_20948_Stat_Ok) && (retval != ICM_20948_Stat_NotImpl))
689+
if (retval != ICM_20948_Stat_Ok)
691690
{
692691
status = retval;
693692
return status;
694693
}
695-
if (retval == ICM_20948_Stat_NotImpl)
696-
{
697-
// This is a temporary fix.
698-
// Ultimately we *should* be able to configure the I2C master to handle the
699-
// magnetometer no matter what interface (SPI / I2C) we are using.
700-
701-
// Should try testing I2C master functionality on a bare ICM chip w/o TXS0108 level shifter...
702-
703-
_has_magnetometer = false;
704-
retval = ICM_20948_Stat_Ok; // reset the retval because we handled it in this cases
705-
}
706694

707-
status = retval;
708695
return status;
709696
}
710697

711-
ICM_20948_Status_e ICM_20948::startupMagnetometer(void)
698+
// direct read/write
699+
ICM_20948_Status_e ICM_20948::read(uint8_t reg, uint8_t *pdata, uint32_t len)
712700
{
713-
return ICM_20948_Stat_NotImpl; // By default we assume that we cannot access the magnetometer
701+
status = ICM_20948_execute_r(&_device, reg, pdata, len);
702+
return (status);
714703
}
715704

716-
ICM_20948_Status_e ICM_20948::getMagnetometerData(ICM_20948_AGMT_t *pagmt)
705+
ICM_20948_Status_e ICM_20948::write(uint8_t reg, uint8_t *pdata, uint32_t len)
717706
{
718-
return ICM_20948_Stat_NotImpl; // By default we assume that we cannot access the magnetometer
707+
status = ICM_20948_execute_w(&_device, reg, pdata, len);
708+
return (status);
719709
}
720710

721-
// direct read/write
722-
ICM_20948_Status_e ICM_20948::read(uint8_t reg, uint8_t *pdata, uint32_t len)
711+
uint8_t ICM_20948::readMag(AK09916_Reg_Addr_e reg)
723712
{
724-
status = ICM_20948_execute_r(&_device, reg, pdata, len);
713+
uint8_t data = i2cMasterSingleR(MAG_AK09916_I2C_ADDR, reg);
714+
return data;
725715
}
726716

727-
ICM_20948_Status_e ICM_20948::write(uint8_t reg, uint8_t *pdata, uint32_t len)
717+
ICM_20948_Status_e ICM_20948::writeMag(AK09916_Reg_Addr_e reg, uint8_t *pdata)
728718
{
729-
status = ICM_20948_execute_w(&_device, reg, pdata, len);
719+
status = i2cMasterSingleW(MAG_AK09916_I2C_ADDR, reg, pdata);
720+
return status;
730721
}
731722

732723
// I2C
@@ -778,103 +769,78 @@ ICM_20948_Status_e ICM_20948_I2C::begin(TwoWire &wirePort, bool ad0val, uint8_t
778769
return status;
779770
}
780771

781-
ICM_20948_Status_e ICM_20948_I2C::startupMagnetometer(void)
772+
ICM_20948_Status_e ICM_20948::startupMagnetometer(void)
782773
{
783-
// If using the magnetometer through passthrough:
784-
i2cMasterPassthrough(true); // Set passthrough mode to try to access the magnetometer (by default I2C master is disabled but you still have to enable the passthrough)
774+
ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
785775

786-
// Try to set up magnetometer
787-
AK09916_CNTL2_Reg_t reg;
788-
reg.MODE = AK09916_mode_cont_100hz;
776+
i2cMasterPassthrough(false); //Do not connect the SDA/SCL pins to AUX_DA/AUX_CL
777+
i2cMasterEnable(true);
789778

790-
ICM_20948_Status_e retval = writeMag(AK09916_REG_CNTL2, (uint8_t *)&reg, sizeof(AK09916_CNTL2_Reg_t));
791-
status = retval;
792-
if (status == ICM_20948_Stat_Ok)
779+
//After a ICM reset the Mag sensor may stop responding over the I2C master
780+
//Reset the Master I2C until it responds
781+
uint8_t tries = 0;
782+
uint8_t maxTries = 5;
783+
while (tries < maxTries)
793784
{
794-
_has_magnetometer = true;
795-
}
796-
return status;
797-
}
798-
799-
ICM_20948_Status_e ICM_20948_I2C::magWhoIAm(void)
800-
{
801-
ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
785+
//See if we can read the WhoIAm register correctly
786+
retval = magWhoIAm();
787+
if (retval == ICM_20948_Stat_Ok)
788+
break; //WIA matched!
802789

803-
const uint8_t len = 2;
804-
uint8_t whoiam[len];
805-
retval = readMag(AK09916_REG_WIA1, whoiam, len);
806-
status = retval;
807-
if (retval != ICM_20948_Stat_Ok)
808-
{
809-
return retval;
790+
i2cMasterReset(); //Otherwise, reset the master I2C and try again
791+
tries++;
810792
}
811793

812-
if ((whoiam[0] == (MAG_AK09916_WHO_AM_I >> 8)) && (whoiam[1] == (MAG_AK09916_WHO_AM_I & 0xFF)))
794+
if (tries == maxTries)
813795
{
814-
retval = ICM_20948_Stat_Ok;
815-
status = retval;
796+
status = ICM_20948_Stat_WrongID;
816797
return status;
817798
}
818-
retval = ICM_20948_Stat_WrongID;
819-
status = retval;
820-
return status;
821-
}
822799

823-
bool ICM_20948_I2C::magIsConnected(void)
824-
{
825-
if (magWhoIAm() != ICM_20948_Stat_Ok)
800+
//Serial.printf("Mag connected tries: %d\n", tries);
801+
802+
//Set up magnetometer
803+
AK09916_CNTL2_Reg_t reg;
804+
reg.MODE = AK09916_mode_cont_100hz;
805+
retval = writeMag(AK09916_REG_CNTL2, (uint8_t *)&reg);
806+
if (retval != ICM_20948_Stat_Ok)
826807
{
827-
return false;
808+
status = retval;
809+
return status;
828810
}
829-
return true;
830-
}
831-
832-
ICM_20948_Status_e ICM_20948_I2C::getMagnetometerData(ICM_20948_AGMT_t *pagmt)
833-
{
834-
835-
const uint8_t reqd_len = 9; // you must read all the way through the status2 register to re-enable the next measurement
836-
uint8_t buff[reqd_len];
837811

838-
status = readMag(AK09916_REG_ST1, buff, reqd_len);
839-
if (status != ICM_20948_Stat_Ok)
812+
retval = i2cMasterConfigureSlave(0, MAG_AK09916_I2C_ADDR, AK09916_REG_ST1, 9, true, true, false, false, false);
813+
if (retval != ICM_20948_Stat_Ok)
840814
{
815+
status = retval;
841816
return status;
842817
}
843818

844-
pagmt->mag.axes.x = ((buff[2] << 8) | (buff[1] & 0xFF));
845-
pagmt->mag.axes.y = ((buff[4] << 8) | (buff[3] & 0xFF));
846-
pagmt->mag.axes.z = ((buff[6] << 8) | (buff[5] & 0xFF));
847-
848819
return status;
849820
}
850821

851-
ICM_20948_Status_e ICM_20948_I2C::readMag(uint8_t reg, uint8_t *pdata, uint8_t len)
822+
ICM_20948_Status_e ICM_20948::magWhoIAm(void)
852823
{
853-
_i2c->beginTransmission(MAG_AK09916_I2C_ADDR);
854-
_i2c->write(reg);
855-
_i2c->endTransmission(false);
824+
ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
856825

857-
uint8_t num_received = _i2c->requestFrom((uint8_t)MAG_AK09916_I2C_ADDR, (uint8_t)len);
858-
if (num_received != len)
826+
uint8_t whoiam1, whoiam2;
827+
whoiam1 = readMag(AK09916_REG_WIA1);
828+
whoiam2 = readMag(AK09916_REG_WIA2);
829+
status = retval;
830+
if (retval != ICM_20948_Stat_Ok)
859831
{
860-
return ICM_20948_Stat_NoData;
832+
return retval;
861833
}
862834

863-
for (uint8_t indi = 0; indi < len; indi++)
835+
if ((whoiam1 == (MAG_AK09916_WHO_AM_I >> 8)) && (whoiam2 == (MAG_AK09916_WHO_AM_I & 0xFF)))
864836
{
865-
*(pdata + indi) = _i2c->read();
837+
retval = ICM_20948_Stat_Ok;
838+
status = retval;
839+
return status;
866840
}
867-
868-
return ICM_20948_Stat_Ok;
869-
}
870-
871-
ICM_20948_Status_e ICM_20948_I2C::writeMag(uint8_t reg, uint8_t *pdata, uint8_t len)
872-
{
873-
_i2c->beginTransmission(MAG_AK09916_I2C_ADDR);
874-
_i2c->write(reg);
875-
_i2c->write(pdata, len);
876-
_i2c->endTransmission();
877-
return ICM_20948_Stat_Ok; // todo: check return of 'endTransmission' to verify all bytes sent w/ ACK
841+
retval = ICM_20948_Stat_WrongID;
842+
status = retval;
843+
return status;
878844
}
879845

880846
// SPI
@@ -923,8 +889,6 @@ ICM_20948_Status_e ICM_20948_SPI::begin(uint8_t csPin, SPIClass &spiPort, uint32
923889
return status;
924890
}
925891

926-
// todo: disable I2C interface to prevent accidents
927-
928892
return ICM_20948_Stat_Ok;
929893
}
930894

src/ICM_20948.h

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ A C++ interface to the ICM-20948
88
#define _ICM_20948_H_
99

1010
#include "util/ICM_20948_C.h" // The C backbone
11+
#include "util/AK09916_REGISTERS.h"
1112

1213
#include "Arduino.h" // Arduino support
1314
#include "Wire.h"
@@ -21,7 +22,6 @@ class ICM_20948
2122
private:
2223
protected:
2324
ICM_20948_Device_t _device;
24-
bool _has_magnetometer;
2525

2626
float getTempC(int16_t val);
2727
float getGyrDPS(int16_t axis_val);
@@ -92,20 +92,28 @@ class ICM_20948
9292
// Interface Options
9393
ICM_20948_Status_e i2cMasterPassthrough(bool passthrough = true);
9494
ICM_20948_Status_e i2cMasterEnable(bool enable = true);
95-
ICM_20948_Status_e i2cMasterConfigureSlave(uint8_t slave, uint8_t addr, uint8_t reg, uint8_t len, bool Rw = true, bool enable = true, bool data_only = false, bool grp = false, bool swap = false);
95+
ICM_20948_Status_e i2cMasterReset();
9696

97+
//Used for configuring slaves 0-3
98+
ICM_20948_Status_e i2cMasterConfigureSlave(uint8_t slave, uint8_t addr, uint8_t reg, uint8_t len, bool Rw = true, bool enable = true, bool data_only = false, bool grp = false, bool swap = false);
9799
ICM_20948_Status_e i2cMasterSLV4Transaction(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len, bool Rw, bool send_reg_addr = true);
100+
101+
//Used for configuring the Magnetometer
98102
ICM_20948_Status_e i2cMasterSingleW(uint8_t addr, uint8_t reg, uint8_t data);
99103
uint8_t i2cMasterSingleR(uint8_t addr, uint8_t reg);
100104

101105
// Default Setup
102106
ICM_20948_Status_e startupDefault(void);
103-
virtual ICM_20948_Status_e startupMagnetometer(void);
104-
virtual ICM_20948_Status_e getMagnetometerData(ICM_20948_AGMT_t *pagmt);
105107

106108
// direct read/write
107109
ICM_20948_Status_e read(uint8_t reg, uint8_t *pdata, uint32_t len);
108110
ICM_20948_Status_e write(uint8_t reg, uint8_t *pdata, uint32_t len);
111+
112+
//Mag specific
113+
ICM_20948_Status_e startupMagnetometer(void);
114+
ICM_20948_Status_e magWhoIAm(void);
115+
uint8_t readMag(AK09916_Reg_Addr_e reg);
116+
ICM_20948_Status_e writeMag(AK09916_Reg_Addr_e reg, uint8_t *pdata);
109117
};
110118

111119
// I2C
@@ -128,13 +136,6 @@ class ICM_20948_I2C : public ICM_20948
128136
ICM_20948_I2C(); // Constructor
129137

130138
virtual ICM_20948_Status_e begin(TwoWire &wirePort = Wire, bool ad0val = true, uint8_t ad0pin = ICM_20948_ARD_UNUSED_PIN);
131-
virtual ICM_20948_Status_e readMag(uint8_t reg, uint8_t *pdata, uint8_t len);
132-
virtual ICM_20948_Status_e writeMag(uint8_t reg, uint8_t *pdata, uint8_t len);
133-
134-
ICM_20948_Status_e startupMagnetometer(void);
135-
ICM_20948_Status_e magWhoIAm(void);
136-
bool magIsConnected(void);
137-
ICM_20948_Status_e getMagnetometerData(ICM_20948_AGMT_t *pagmt);
138139
};
139140

140141
// SPI

0 commit comments

Comments
 (0)