Skip to content

Commit 2946121

Browse files
authored
Fix/moved mag reset outside of constructor (#33)
* removed mag and icm reset calls from constructor; included the calls in the demo file * moved only the rest_mag() outside of the constructor for a consistent and reliable startup of icm * added steady clock into the icm as well as other supporting functions * specified the error catch to hal::no_such_device and removed having steady clock as a member var
1 parent 3b1c208 commit 2946121

2 files changed

Lines changed: 88 additions & 4 deletions

File tree

include/libhal-sensor/imu/icm20948.hpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,18 @@ class icm20948
224224
* @brief private constructor for icm20948 objects
225225
* @param p_i2c The I2C peripheral used for communication with the device.
226226
*/
227-
icm20948(hal::i2c& p_i2c);
227+
[[deprecated(
228+
"Use the constructor with hal::steady_clock instead.")]] icm20948(hal::i2c&
229+
p_i2c);
230+
231+
/**
232+
* @brief private constructor for icm20948 objects
233+
* @param p_i2c The I2C peripheral used for communication with the device.
234+
* @param p_steady_clock After an ICM reset, the I2C master may not be ready;
235+
thus, the Clock peripheral is used to provide delay until I2C master is
236+
ready.
237+
*/
238+
icm20948(hal::i2c& p_i2c, hal::steady_clock& p_steady_clock);
228239

229240
void auto_offsets();
230241

@@ -252,8 +263,8 @@ class icm20948
252263
void set_acc_dlpf(digital_lowpass_filter p_dlpf);
253264
void set_acc_sample_rate_div(uint16_t p_acc_spl_rate_div);
254265
void enable_gyro(bool p_enable_gyro);
255-
[[deprecated("Use the API `enable_gyro()` with a full name.")]]
256-
void enable_gyr(bool p_enable_gyro)
266+
[[deprecated("Use the API `enable_gyro()` with a full name.")]] void
267+
enable_gyr(bool p_enable_gyro)
257268
{
258269
enable_gyro(p_enable_gyro);
259270
}
@@ -278,10 +289,13 @@ class icm20948
278289
hal::byte check_mag_mode();
279290
hal::byte whoami_ak09916_wia1_direct();
280291
hal::byte whoami_ak09916_wia2_direct();
292+
[[nodiscard]] bool mag_whoami_ok();
281293
void set_mag_op_mode(ak09916_op_mode p_op_mode);
282294
void write_ak09916_register8(hal::byte p_reg, hal::byte p_val);
283295

284296
private:
297+
static constexpr std::uint8_t max_magnetometer_starts = 5;
298+
285299
void set_clock_auto_select();
286300
void switch_bank(hal::byte p_new_bank);
287301

@@ -312,6 +326,7 @@ class icm20948
312326
void enable_mag_data_read(hal::byte p_reg, hal::byte p_bytes);
313327

314328
void reset_icm20948();
329+
void reset_i2c_master();
315330

316331
/* The I2C peripheral used for communication with the device. */
317332
hal::i2c* m_i2c;

src/imu/icm20948.cpp

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ constexpr hal::byte temp_config = 0x53;
9696
/* Registers ICM20948 USER BANK 3*/
9797
[[maybe_unused]] constexpr hal::byte i2c_mst_odr_cfg = 0x00;
9898
[[maybe_unused]] constexpr hal::byte i2c_mst_ctrl = 0x01;
99-
[[maybe_unused]] constexpr hal::byte i2c_mst_delay_ctrl = 0x02;
99+
constexpr hal::byte i2c_mst_delay_ctrl = 0x02;
100100
constexpr hal::byte i2c_slv0_addr = 0x03;
101101
constexpr hal::byte i2c_slv0_reg = 0x04;
102102
constexpr hal::byte i2c_slv0_ctrl = 0x05;
@@ -177,6 +177,53 @@ icm20948::icm20948(hal::i2c& p_i2c)
177177
write_register8({ .bank = 2, .reg = odr_align_en, .val = 1 }); // aligns ODR
178178
}
179179

180+
icm20948::icm20948(hal::i2c& p_i2c, hal::steady_clock& p_steady_clock)
181+
: m_i2c(&p_i2c)
182+
{
183+
m_current_bank = 0;
184+
185+
reset_icm20948();
186+
hal::delay(*p_steady_clock, 100ms);
187+
set_clock_auto_select();
188+
sleep(false);
189+
hal::delay(*p_steady_clock, 10ms);
190+
reset_mag();
191+
192+
std::uint8_t tries = 0;
193+
while (tries < max_magnetometer_starts) {
194+
tries++;
195+
196+
if (mag_whoami_ok()) {
197+
break;
198+
}
199+
200+
i2c_master_reset();
201+
hal::delay(*p_steady_clock, 10ms);
202+
}
203+
204+
if (auto id = whoami(); id != who_am_i_content) {
205+
hal::safe_throw(hal::no_such_device(id, this));
206+
}
207+
208+
m_acc_offset_val.x = 0.0;
209+
m_acc_offset_val.y = 0.0;
210+
m_acc_offset_val.z = 0.0;
211+
m_acc_corr_factor.x = 1.0;
212+
m_acc_corr_factor.y = 1.0;
213+
m_acc_corr_factor.z = 1.0;
214+
m_acc_range_factor = 1.0;
215+
m_gyro_offset_val.x = 0.0;
216+
m_gyro_offset_val.y = 0.0;
217+
m_gyro_offset_val.z = 0.0;
218+
m_gyro_range_factor = 1.0;
219+
220+
sleep(false);
221+
enable_acc(true);
222+
enable_gyro(true);
223+
224+
write_register8({ .bank = 2, .reg = odr_align_en, .val = 1 }); // aligns ODR
225+
}
226+
180227
void icm20948::auto_offsets()
181228
{
182229
set_gyro_dlpf(dlpf_6); // lowest noise
@@ -662,4 +709,26 @@ void icm20948::enable_mag_data_read(hal::byte p_reg, // NOLINT
662709
hal::byte const enable_and_bytes = 0x80 | p_bytes;
663710
write_register8({ .bank = 3, .reg = i2c_slv0_ctrl, .val = enable_and_bytes });
664711
}
712+
713+
bool icm20948::mag_whoami_ok()
714+
{
715+
try {
716+
enable_bypass_mode();
717+
718+
auto const wia1 = whoami_ak09916_wia1_direct();
719+
auto const wia2 = whoami_ak09916_wia2_direct();
720+
721+
return (wia1 == static_cast<hal::byte>(ak09916_who_am_i_1)) &&
722+
(wia2 == static_cast<hal::byte>(ak09916_who_am_i_2));
723+
} catch (hal::no_such_device const&) {
724+
return false;
725+
}
726+
}
727+
728+
void icm20948::reset_i2c_master()
729+
{
730+
auto ctrl = read_register8({ .bank = 0, .reg = user_ctrl });
731+
ctrl |= i2c_mst_delay_ctrl;
732+
write_register8({ .bank = 0, .reg = user_ctrl, .val = ctrl });
733+
}
665734
} // namespace hal::sensor

0 commit comments

Comments
 (0)