This is more of question than an actual bug. It seems that for the nRF52 chips, the I2C address of devices has to be shifted with 1 (addr << 1). This prevents components from working, as components place the actual address in the capsule.
One workaround that I did is to write a macro that allows specifying the address manually as shown in the next example:
macro_rules! lsm303agr_i2c_component_helper {
($i2c_mux:expr, $accelerometer_address:expr, $magnetometer_address:expr $(,)?) => {{
use capsules::lsm303agr::Lsm303agrI2C;
use capsules::virtual_i2c::I2CDevice;
use core::mem::MaybeUninit;
static mut BUFFER: [u8; 8] = [0; 8];
let accelerometer_i2c =
components::i2c::I2CComponent::new($i2c_mux, $accelerometer_address)
.finalize(components::i2c_component_helper!());
let magnetometer_i2c = components::i2c::I2CComponent::new($i2c_mux, $magnetometer_address)
.finalize(components::i2c_component_helper!());
static mut lsm303agr: MaybeUninit<Lsm303agrI2C<'static>> = MaybeUninit::uninit();
(
&accelerometer_i2c,
&magnetometer_i2c,
&mut BUFFER,
&mut lsm303agr,
)
}};
($i2c_mux:expr $(,)?) => {{
$crate::lsm303agr_i2c_component_helper!(
$i2c_mux,
capsules::lsm303agr::ACCELEROMETER_BASE_ADDRESS,
capsules::lsm303agr::MAGNETOMETER_BASE_ADDRESS
)
}};
}
I am not sure why the address needs to be shifted, I am guessing it is due to the R/W bit.
Is there any impact of changing the TWIM for nRF to take the address as a parameter instead of the shifted address? The driver shifts it back anyway.
fn write_read(&self, addr: u8, data: &'static mut [u8], write_len: u8, read_len: u8) {
self.registers
.address
.write(ADDRESS::ADDRESS.val((addr >> 1) as u32));
self.registers.txd_ptr.set(data.as_mut_ptr());
// ...
modified
fn write_read(&self, addr: u8, data: &'static mut [u8], write_len: u8, read_len: u8) {
self.registers
.address
.write(ADDRESS::ADDRESS.val(addr as u32));
self.registers.txd_ptr.set(data.as_mut_ptr());
// ...
The shift in the address would be because that is how the packet it sent over the wire: https://www.i2c-bus.org/addressing/
The address is the first 7 bits sent and the R/W bit is the last bit sent.
I would say that the address should always be passed and used unshifted. Only the final write to hardware should shift the address if required. This is because not all hardware requires a shifted address. Some implementations for example write the address to a register and the hardware will handle the rest automatically.
I agree, I would modify the driver and send a PR. I just wanted to make sure that there is no other reason for this.
Most helpful comment
I agree, I would modify the driver and send a PR. I just wanted to make sure that there is no other reason for this.