-
Notifications
You must be signed in to change notification settings - Fork 522
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Newer revisions use LSM303AGR instead of LSM303DLHC #274
Comments
Thanks for noticing. I have a WIP driver for the LSM303AGR so you can at least play around with that. |
That's great news! Even with the discrepancies the book has, I found this book extremely helpful with dipping my toes into the embedded rust world, and updating the book will help countless more people. |
Additionally, to make the |
This is for anyone working through the book and you're stuck at the Here is the link for the LSM303AGR data sheet. As noted above, newer board revisions use this For a quick test the If successfully you should see So the code from the book becomes:
|
Until there is a rewrite, is it possible to flag this divergence (more?) prominently in the book? Akin to how the missing solder bridge is nice and big and hard to miss (which I still managed to miss on first read). |
@waalge Sure thing. We would be glad about PRs doing that. |
300: add two notes flagging lsm303agr r=eldruin a=waalge In response to #274 (comment) Please edit at leisure / suggest anything Co-authored-by: waalge <[email protected]>
Happy to do more with instruction/ pointers. When does the book get rebuilt so that changes appear? |
The one hosted at https://rust-embedded.github.io/discovery should be rebuilt shortly after each PR merge. The one hosted at https://docs.rust-embedded.org/discovery is a bit outdated because our CI for it is currently broken. We recently had some discussion about solving this and only publishing one version. |
Indeed this helped me get to a solution for the Here's my implementation for reading the magnetometer continuously.
|
Also note that the code to convert from the 6 register readings to 3 x i16 have the LSB/MSB order mixed up it should be LSB first :
|
@folknology thanks! I'm seeing that the registers are in order x, then y, then z. This is giving me the results I'm getting from using the |
Hi, I suspect that I have a board with
The book points to this thread but there don't seem to be any solutions to this problem here. What should be modified? Looking at the Edit: Ok, took a while but I managed to figure something out. Not sure if this is the appropriate place to post this, but hopefully it helps someone. I was using the In [dependencies]
cortex-m = "0.7"
cortex-m-rt = { version = "0.7", features = ["device"] }
panic-itm = "0.4"
stm32f3xx-hal = { version = "0.8", features = ["ld", "rt", "stm32f303xc"] }
lsm303agr = "0.2" In #![deny(unsafe_code)]
#![no_std]
#![no_main]
use core::convert::TryInto;
use cortex_m::{asm, iprintln};
use cortex_m_rt::entry;
use lsm303agr::Lsm303agr;
use panic_itm as _;
use stm32f3xx_hal::{self as hal, pac, prelude::*};
#[entry]
fn main() -> ! {
let cp = cortex_m::Peripherals::take().unwrap();
let mut itm = cp.ITM;
let dp = pac::Peripherals::take().unwrap();
let mut flash = dp.FLASH.constrain();
let mut rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.freeze(&mut flash.acr);
let mut gpiob = dp.GPIOB.split(&mut rcc.ahb);
let mut scl =
gpiob
.pb6
.into_af4_open_drain(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl);
let mut sda =
gpiob
.pb7
.into_af4_open_drain(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl);
scl.internal_pull_up(&mut gpiob.pupdr, true);
sda.internal_pull_up(&mut gpiob.pupdr, true);
let i2c = hal::i2c::I2c::new(
dp.I2C1,
(scl, sda),
400.kHz().try_into().unwrap(),
clocks,
&mut rcc.apb1,
);
let mut sensor = Lsm303agr::new_with_i2c(i2c);
sensor
.set_mag_odr(lsm303agr::MagOutputDataRate::Hz10)
.unwrap();
loop {
match sensor.mag_data() {
Ok(val) => iprintln!(&mut itm.stim[0], "{:?}", val),
Err(_) => asm::delay(1_000_000),
}
}
} |
Hello. I was working through this and got stuck here. I followed @wbuck's example above but there isn't a |
@davemo88 From f3's reference manual, page: 87 // For 7 bit address, we populate bits 1 through 7 of SADD
// This gives me output that matches `lsm303agr` crate
w.sadd().bits((MAGNETOMETER << 1).into()); |
In the latest version the magnetometer data can be obtained correctly using the following code. #![deny(unsafe_code)]
#![no_main]
#![no_std]
use aux14::i2c1::RegisterBlock;
#[allow(unused_imports)]
use aux14::{entry, iprint, iprintln, prelude::*};
// Slave address
const MAGNETOMETER: u16 = 0b0011_1100;
// Addresses of the magnetometer's registers
const WHO_AM_I_M: u8 = 0x4F;
const CFG_REG_A_M: u8 = 0x60;
const OUTX_L_REG_M: u8 = 0x068;
#[entry]
fn main() -> ! {
let (i2c1, mut delay, mut itm) = aux14::init();
let cfg_reg_a_m_byte: u8 = set_mode_continuous__LSM303AGR(i2c1);
// Expected output: 0x60 - 0b00000000
iprintln!(
&mut itm.stim[0],
"0x{:02X} - 0b{:08b}",
CFG_REG_A_M,
cfg_reg_a_m_byte
);
let whoami: u8 = who_am_i__LSM303AGR(i2c1);
// Expected output: 0x4F - 0b01000000
iprintln!(&mut itm.stim[0], "0x{:02X} - 0b{:08b}", WHO_AM_I_M, whoami);
loop {
// ask for an array of 6 register values starting at OUTX_L_REG_M (0x68)
{
// Broadcast START
// Broadcast the MAGNETOMETER address with the R/W bit set to Write
i2c1.cr2.write(|w| {
w.start().set_bit();
w.sadd().bits(MAGNETOMETER);
w.rd_wrn().clear_bit();
w.nbytes().bits(1);
w.autoend().clear_bit()
});
// Wait until we can send more data
while i2c1.isr.read().txis().bit_is_clear() {}
// Send the address of the register that we want to read: WHO_AM_I_M
i2c1.txdr.write(|w| w.txdata().bits(OUTX_L_REG_M));
// Wait until the previous byte has been transmitted
while i2c1.isr.read().tc().bit_is_clear() {}
}
i2c1.cr2.modify(|_, w| {
w.start().set_bit();
w.nbytes().bits(6);
w.rd_wrn().set_bit();
w.autoend().set_bit()
});
let mut buffer = [0u8; 6];
for byte in &mut buffer {
// Wait until we have received something
while i2c1.isr.read().rxne().bit_is_clear() {}
*byte = i2c1.rxdr.read().rxdata().bits();
}
// Broadcast STOP (automatic because of `AUTOEND = 1`)
iprintln!(&mut itm.stim[0], "{:?}", buffer);
let x_l = u16::from(buffer[0]);
let x_h = u16::from(buffer[1]);
let y_l = u16::from(buffer[2]);
let y_h = u16::from(buffer[3]);
let z_l = u16::from(buffer[4]);
let z_h = u16::from(buffer[5]);
let x = ((x_h << 8) + x_l) as i16;
let y = ((y_h << 8) + y_l) as i16;
let z = ((z_h << 8) + z_l) as i16;
iprintln!(&mut itm.stim[0], "{:?}", (x, y, z));
delay.delay_ms(1_000_u16);
}
}
fn who_am_i__LSM303AGR(i2c1: &RegisterBlock) -> u8 {
// Stage 1: Send the address of the register we want to read to the
// magnetometer
{
// Broadcast START
// Broadcast the MAGNETOMETER address with the R/W bit set to Write
i2c1.cr2.write(|w| {
w.start().set_bit();
w.sadd().bits(MAGNETOMETER);
w.rd_wrn().clear_bit();
w.nbytes().bits(1);
w.autoend().clear_bit()
});
// Wait until we can send more data
while i2c1.isr.read().txis().bit_is_clear() {}
// Send the address of the register that we want to read: WHO_AM_I_M
i2c1.txdr.write(|w| w.txdata().bits(WHO_AM_I_M));
// Wait until the previous byte has been transmitted
while i2c1.isr.read().tc().bit_is_clear() {}
}
// Stage 2: Receive the contents of the register we asked for
let byte = {
// Broadcast RESTART
// Broadcast the MAGNETOMETER address with the R/W bit set to Read.
i2c1.cr2.modify(|_, w| {
w.start().set_bit();
w.nbytes().bits(1);
w.rd_wrn().set_bit();
w.autoend().set_bit()
});
// Wait until we have received the contents of the register
while i2c1.isr.read().rxne().bit_is_clear() {}
// Broadcast STOP (automatic because of `AUTOEND = 1`)
i2c1.rxdr.read().rxdata().bits()
};
byte
}
fn set_mode_continuous__LSM303AGR(i2c1: &RegisterBlock) -> (u8) {
{
// Broadcast START
// Broadcast the MAGNETOMETER address with the R/W bit set to Write
i2c1.cr2.write(|w| {
w.start().set_bit();
w.sadd().bits(MAGNETOMETER);
w.rd_wrn().clear_bit();
w.nbytes().bits(2);
w.autoend().clear_bit()
});
// Wait until we can send more data
while i2c1.isr.read().txis().bit_is_clear() {}
// Send the address of the register that we want to read: WHO_AM_I_M
i2c1.txdr.write(|w| w.txdata().bits(CFG_REG_A_M));
i2c1.txdr.write(|w| w.txdata().bits(0x0));
// Wait until the previous byte has been transmitted
while i2c1.isr.read().tc().bit_is_clear() {}
}
let cfg_reg_a_m_byte = {
// Broadcast RESTART
// Broadcast the MAGNETOMETER address with the R/W bit set to Read.
i2c1.cr2.modify(|_, w| {
w.start().set_bit();
w.nbytes().bits(1);
w.rd_wrn().set_bit();
w.autoend().set_bit()
});
// Wait until we have received the contents of the register
while i2c1.isr.read().rxne().bit_is_clear() {}
// Broadcast STOP (automatic because of `AUTOEND = 1`)
i2c1.rxdr.read().rxdata().bits()
};
cfg_reg_a_m_byte
} |
@al-jshen Just another datapoint: I had the same problem that you describe, but for me it was fixed simply by restarting everything (board & openocd). 🤷 |
Newer revisions of the discovery board use the
LSM303AGR
instead of theLSM303DLHC
. The I2C address of theLSM303AGR
chip is still the same but the registers to read are different. This makes it very confusing, as the code doesn't end up panicking, only returning zeros or garbage data.The text was updated successfully, but these errors were encountered: