Skip to content
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

impl new i2c driver interface of esp-idf 5.2 #397

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

teamplayer3
Copy link
Contributor

@teamplayer3 teamplayer3 commented Mar 21, 2024

closes #388

Interface

Sync

let config = Config {
    pub pullup_enabled: bool,
    pub source_clock: SourceClock,
    pub glitch_ignore_cnt: u8,
};

let driver = I2cDriver::new(..., config);

let config = DeviceConfig {
    pub address: DeviceAddress,
    pub baudrate: Hertz,
}

let device_a = I2cDeviceDriver::new(&driver, config).unwrap();
let device_b = I2cDeviceDriver::new(&driver, config).unwrap();

Async

let config = Config {
    pub pullup_enabled: bool,
    pub source_clock: SourceClock,
    pub glitch_ignore_cnt: u8,
};

let driver = AsyncI2cDriver::new(..., config);

let config = DeviceConfig {
    pub address: DeviceAddress,
    pub baudrate: Hertz,
}

let device_a = AsyncI2cDeviceDriver::new(&driver, config).unwrap();
// will fail (only one async device per bus)
let device_b = AsyncI2cDeviceDriver::new(&driver, config).unwrap();
let device_c = I2cDeviceDriver::new(&driver, config).unwrap();

trait impls

  • I2cDriver: impls embedded_hal traits by creating a device driver internally by using default device config (transaction unimplemented!)
  • AsyncI2cDriver: impls embedded_hal_async traits by creating a device driver internally by using default device config (transaction unimplemented!)
  • I2cDeviceDriver: impls embedded_hal traits by ignoring the address args of the trait (transaction unimplemented!)
  • AsyncI2cDeviceDriver: impls embedded_hal traits and embedded_hal_async traits by ignoring the address args of the trait (transaction unimplemented!)

Open Questions:

  • Is it ok to split the drivers into sync and async drivers? Main difference when using async (alternative: blocking and not blocking into one driver and depend on the esp-idf runtime checks if async is enabled for the bus)
    • add the isr callback (only one device can be async at a time)
    • increase the trans_queue_depth config (this must be done at driver creation time) (as it is implemented by now, the implementation takes care of it, but if we combine the drivers it could be done by the user in the driver config and by adding a comment to indicate to increase it when doing async operations)
  • How to support legacy driver (transactional interface)
    • call it LegacyI2cDriver?
    • How to deal with it if two i2c drivers can be used? (must be both legacy or new driver)
  • support sync and async on one bus? The current implementation allows only sync or async devices.
  • Use case for setting trans_queue_depth > 1?
  • How to impl read blocking for I2cSlaveDriver?
  • Allow 7/10 bit address (currently in dev config, but embedded_hal needs it within the type itself -> add a generic to the device driver whether it is 7 or 10 bit address)

sync and async driver combined + address len

// only sync operations available
let driver = I2cDriver::<'_, AsyncDisabled>::new(..., config);
// async operations + async devices available
let driver = I2cDriver::<'_, AsyncEnabled>::new(..., config); // sets `trans_queue_depth` = 1

let sync_device = driver.device::<TenBitAddress>(config);
drop(sync_device);
let owned_sync_device = driver.owned_device(config); // bus is owned by the device
let driver = owned_sync_device.release();
// if AsyncEnabled
let async_device = driver.async_device(config);
drop(async_device);
let owned_async_device = driver.owned_async_device(config); // bus is owned by the device
let driver = owned_async_device.release();

(Not really working like this. It could work if we call the driver impl something like GenericI2cDriver and publish a type for the blocking driver as type I2cDriver<'d> = GenericI2cDriver<'d, AsyncDisabled> and for async type I2cDriver<'d> = GenericI2cDriver<'d, AsyncEnabled>

pros

  • less code for both impls.

cons

  • adds a confusing GenericI2cDriver type

other sync and async driver combination solution

Don't use type system. Depend on the runtime check and the thrown error by the esp-idf when using an async function if the bus is not configured correctly. The user must set the bus config correct to enable async capabilities.

@teamplayer3
Copy link
Contributor Author

teamplayer3 commented Mar 21, 2024

When I use the OwnedAsyncI2cDeviceDriver async driver (do some operations) as I implemented it, I get an error with the following backtrace. If I add some dbg!() in the read, write or write_read operations it works fine. So it is mainly because of the call to the fast HalIsrNotification::wait()? @ivmarkov Some ideas why?

stacktrace
Guru Meditation Error: Core  0 panic'ed (Stack protection fault).

Detected in task "pthread" at 0x40387f16
0x40387f16 - multi_heap_internal_lock
    at /home/al9hu7/workspace/playground/i2c-test/.embuild/espressif/esp-idf/v5.2.1/components/heap/multi_heap.c:164
Stack pointer: 0x3fc99910
0x3fc99910 - _heap_start
    at ??:??
Stack bounds: 0x3fc9991c - 0x3fc9a510
0x3fc9991c - _heap_start
    at ??:??
0x3fc9a510 - _heap_start
    at ??:??


Core  0 register dump:
MEPC    : 0x40387f1e  RA      : 0x40387e7e  SP      : 0x3fc99910  GP      : 0x3fc8b600
0x40387f1e - multi_heap_internal_lock
    at /home/al9hu7/workspace/playground/i2c-test/.embuild/espressif/esp-idf/v5.2.1/components/heap/multi_heap.c:166
0x40387e7e - multi_heap_aligned_alloc_impl_offs
    at /home/al9hu7/workspace/playground/i2c-test/.embuild/espressif/esp-idf/v5.2.1/components/heap/multi_heap.c:286
0x3fc99910 - _heap_start
    at ??:??
0x3fc8b600 - __global_pointer$
    at ??:??
TP      : 0x3fc73940  T0      : 0x42031486  T1      : 0x40389c72  T2      : 0xa5a5a5a5
0x3fc73940 - _rodata_reserved_end
    at ??:??
0x42031486 - core::sync::atomic::atomic_compare_exchange
    at /home/al9hu7/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/sync/atomic.rs:3388
0x40389c72 - memspi_host_read_id_hs
    at /home/al9hu7/workspace/playground/i2c-test/.embuild/espressif/esp-idf/v5.2.1/components/spi_flash/memspi_host_driver.c:113
0xa5a5a5a5 - SYSTEM
    at ??:??
S0/FP   : 0x3fc8d590  S1      : 0x00000008  A0      : 0x00000000  A1      : 0x00000008
0x3fc8d590 - _heap_start
    at ??:??
0x00000008 - RV_STK_SP
    at ??:??
0x00000000 -
    at ??:??
0x00000008 - RV_STK_SP
    at ??:??
A2      : 0x00000008  A3      : 0x00000000  A4      : 0x00000000  A5      : 0x3fc8d000
0x00000008 - RV_STK_SP
    at ??:??
0x00000000 -
    at ??:??
0x00000000 -
    at ??:??
0x3fc8d000 - __lock___malloc_recursive_mutex
    at ??:??
A6      : 0x3fc9a77c  A7      : 0xa5a5a5a5  S2      : 0x00000008  S3      : 0x3fc8d940
0x3fc9a77c - _heap_start
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0x00000008 - RV_STK_SP
    at ??:??
0x3fc8d940 - _heap_start
    at ??:??
S4      : 0x00000000  S5      : 0x00000003  S6      : 0x3fc8d000  S7      : 0x00000000
0x00000000 -
    at ??:??
0x00000003 - EXC_ILLEGAL_INSTRUCTION
    at ??:??
0x3fc8d000 - __lock___malloc_recursive_mutex
    at ??:??
0x00000000 -
    at ??:??
S8      : 0x3fc8d590  S9      : 0x3b9aca00  S10     : 0x3c072db8  S11     : 0x3fc8ae10
0x3fc8d590 - _heap_start
    at ??:??
0x3b9aca00 -
    at ??:??
0x3c072db8 - str.0
    at ??:??
0x3fc8ae10 - _ZN12tracing_core8metadata9MAX_LEVEL17h4af3cbd1cee9ec55E
    at ??:??
T3      : 0xa5a5a5a5  T4      : 0xa5a5a5a5  T5      : 0xa5a5a5a5  T6      : 0xa5a5a5a5
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
MSTATUS : 0x00001881  MTVEC   : 0x40380001  MCAUSE  : 0x0000001b  MTVAL   : 0x00000141
0x00001881 -
    at ??:??
0x40380001 - _vector_table
    at ??:??
0x0000001b - _rtc_reserved_length
    at ??:??
0x00000141 -
    at ??:??
MHARTID : 0x00000000
0x00000000 -
    at ??:??

Stack memory:
3fc99910: 0x00000000 0x3fc998dc 0x00000c00 0x40387e7e 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0x00000000
0x00000000 -
    at ??:??
0x3fc998dc - _heap_start
    at ??:??
0x00000c00 -
    at ??:??
0x40387e7e - multi_heap_aligned_alloc_impl_offs
    at /home/al9hu7/workspace/playground/i2c-test/.embuild/espressif/esp-idf/v5.2.1/components/heap/multi_heap.c:286
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0x00000000 -
    at ??:??
3fc99930: 0x00000008 0x00001000 0x00000008 0x403817f8 0xa5a5a5a5 0xa5a5a5a5 0x00000001 0x3b9ad000
0x00000008 - RV_STK_SP
    at ??:??
0x00001000 -
    at ??:??
0x00000008 - RV_STK_SP
    at ??:??
0x403817f8 - heap_caps_aligned_alloc
    at /home/al9hu7/workspace/playground/i2c-test/.embuild/espressif/esp-idf/v5.2.1/components/heap/heap_caps.c:720
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0x00000001 -
    at ??:??
0x3b9ad000 -
    at ??:??
3fc99950: 0x3fc99b48 0x3fc9a79c 0x3b9aca00 0x3b9ad000 0x3fc8d000 0x00000008 0x00000008 0x4202946e
0x3fc99b48 - _heap_start
    at ??:??
0x3fc9a79c - _heap_start
    at ??:??
0x3b9aca00 -
    at ??:??
0x3b9ad000 -
    at ??:??
0x3fc8d000 - __lock___malloc_recursive_mutex
    at ??:??
0x00000008 - RV_STK_SP
    at ??:??
0x00000008 - RV_STK_SP
    at ??:??
0x4202946e - core::ptr::non_null::NonNull<T>::new
    at /home/al9hu7/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/non_null.rs:247
3fc99970: 0x00000000 0x00000008 0x00000008 0x4202936c 0x00000000 0x3fc9a79c 0x3fc9a79c 0x420298a4
0x00000000 -
    at ??:??
0x00000008 - RV_STK_SP
    at ??:??
0x00000008 - RV_STK_SP
    at ??:??
0x4202936c - alloc::alloc::exchange_malloc
    at /home/al9hu7/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/alloc.rs:330
0x00000000 -
    at ??:??
0x3fc9a79c - _heap_start
    at ??:??
0x3fc9a79c - _heap_start
    at ??:??
0x420298a4 - alloc::boxed::Box<T>::new
    at /home/al9hu7/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/boxed.rs:218
3fc99990: 0x00000000 0x3fc8d000 0x00060000 0x00000000 0x00000000 0x3fc8d000 0x3fc9a774 0x3fc9a77c
0x00000000 -
    at ??:??
0x3fc8d000 - __lock___malloc_recursive_mutex
    at ??:??
0x00060000 -
    at ??:??
0x00000000 -
    at ??:??
0x00000000 -
    at ??:??
0x3fc8d000 - __lock___malloc_recursive_mutex
    at ??:??
0x3fc9a774 - _heap_start
    at ??:??
0x3fc9a77c - _heap_start
    at ??:??
3fc999b0: 0x3fc99b48 0x3fc9a79c 0x3fc9a79c 0x42031472 0x00000001 0x3fc99a10 0x3fc9a79c 0x4202fa3a
0x3fc99b48 - _heap_start
    at ??:??
0x3fc9a79c - _heap_start
    at ??:??
0x3fc9a79c - _heap_start
    at ??:??
0x42031472 - std::sys_common::lazy_box::LazyBox<T>::initialize
    at ??:??
0x00000001 -
    at ??:??
0x3fc99a10 - _heap_start
    at ??:??
0x3fc9a79c - _heap_start
    at ??:??
0x4202fa3a - std::sys_common::lazy_box::LazyBox<T>::get_pointer
    at /home/al9hu7/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys_common/lazy_box.rs:50
3fc999d0: 0x3fc99b4c 0x3fc99a20 0x3fc9a79c 0x4202fa60 0x3fc99b4c 0x00000002 0x00000000 0x4202f63c
0x3fc99b4c - _heap_start
    at ??:??
0x3fc99a20 - _heap_start
    at ??:??
0x3fc9a79c - _heap_start
    at ??:??
0x4202fa60 - std::sys::pal::unix::locks::pthread_mutex::Mutex::lock
    at /home/al9hu7/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/pal/unix/locks/pthread_mutex.rs:114
0x3fc99b4c - _heap_start
    at ??:??
0x00000002 - EXC_ILLEGAL_INSTRUCTION
    at ??:??
0x00000000 -
    at ??:??
0x4202f63c - std::sync::mutex::Mutex<T>::lock
    at /home/al9hu7/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sync/mutex.rs:274
3fc999f0: 0x00000000 0x00000001 0x3fc9a7ac 0x42010136 0x00000003 0x00000000 0x00000001 0x4200f154
0x00000000 -
    at ??:??
0x00000001 -
    at ??:??
0x3fc9a7ac - _heap_start
    at ??:??
0x42010136 - core::result::Result<T,E>::unwrap
    at /home/al9hu7/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs:1075
0x00000003 - EXC_ILLEGAL_INSTRUCTION
    at ??:??
0x00000000 -
    at ??:??
0x00000001 -
    at ??:??
0x4200f154 - event_listener::sys::<impl event_listener::Inner<T>>::register
    at /home/al9hu7/.cargo/registry/src/index.crates.io-6f17d22bba15001f/event-listener-4.0.3/src/std.rs:169
3fc99a10: 0x3fc9a6b8 0x3fc9a6bc 0x000f4200 0xa5a5a500 0x00000000 0xa5a5a5a5 0x00001800 0x4038146a
0x3fc9a6b8 - _heap_start
    at ??:??
0x3fc9a6bc - _heap_start
    at ??:??
0x000f4200 -
    at ??:??
0xa5a5a500 - SYSTEM
    at ??:??
0x00000000 -
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0x00001800 -
    at ??:??
0x4038146a - heap_caps_malloc_base
    at /home/al9hu7/workspace/playground/i2c-test/.embuild/espressif/esp-idf/v5.2.1/components/heap/heap_caps.c:180
3fc99a30: 0x00001800 0x00000002 0x00000000 0x3fc9a794 0x00000000 0x3fc9a6b8 0x3fc9a774 0x00000001
0x00001800 -
    at ??:??
0x00000002 - EXC_ILLEGAL_INSTRUCTION
    at ??:??
0x00000000 -
    at ??:??
0x3fc9a794 - _heap_start
    at ??:??
0x00000000 -
    at ??:??
0x3fc9a6b8 - _heap_start
    at ??:??
0x3fc9a774 - _heap_start
    at ??:??
0x00000001 -
    at ??:??
3fc99a50: 0x3fc9a77c 0x3b9aca00 0x3fc99b48 0x4200ed1c 0x00001800 0x0000001c 0x0000001c 0x40381484
0x3fc9a77c - _heap_start
    at ??:??
0x3b9aca00 -
    at ??:??
0x3fc99b48 - _heap_start
    at ??:??
0x4200ed1c - event_listener::Listener<T,B>::wait_with_parker
    at /home/al9hu7/.cargo/registry/src/index.crates.io-6f17d22bba15001f/event-listener-4.0.3/src/lib.rs:1103
0x00001800 -
    at ??:??
0x0000001c - RV_STK_T2
    at ??:??
0x0000001c - RV_STK_T2
    at ??:??
0x40381484 - heap_caps_malloc
    at /home/al9hu7/workspace/playground/i2c-test/.embuild/espressif/esp-idf/v5.2.1/components/heap/heap_caps.c:202
3fc99a70: 0x3b9aca00 0x3fc8d000 0x0000001c 0x4200fe94 0x00000000 0x00000000 0x00000000 0x42010032
0x3b9aca00 -
    at ??:??
0x3fc8d000 - __lock___malloc_recursive_mutex
    at ??:??
0x0000001c - RV_STK_T2
    at ??:??
0x4200fe94 - core::ptr::non_null::NonNull<T>::new
    at /home/al9hu7/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/non_null.rs:247
0x00000000 -
    at ??:??
0x00000000 -
    at ??:??
0x00000000 -
    at ??:??
0x42010032 - alloc::boxed::Box<T>::new
    at /home/al9hu7/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/boxed.rs:218
3fc99a90: 0x00000000 0x00000008 0x000f4240 0x3fc8d348 0x00000000 0x3fc99b48 0x3b9ad000 0x3fc99b48
0x00000000 -
    at ??:??
0x00000008 - RV_STK_SP
    at ??:??
0x000f4240 -
    at ??:??
0x3fc8d348 - _ZN8async_io6driver14BLOCK_ON_COUNT17h0162ff7491fbbacaE
    at ??:??
0x00000000 -
    at ??:??
0x3fc99b48 - _heap_start
    at ??:??
0x3b9ad000 -
    at ??:??
0x3fc99b48 - _heap_start
    at ??:??
3fc99ab0: 0x3b9aca00 0x3fc9a774 0x3fc9a770 0x4200ec30 0x3fc9a6bc 0x00000000 0x3c072e00 0x00000006
0x3b9aca00 -
    at ??:??
0x3fc9a774 - _heap_start
    at ??:??
0x3fc9a770 - _heap_start
    at ??:??
0x4200ec30 - core::cell::Cell<T>::get
    at /home/al9hu7/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/cell.rs:512
0x3fc9a6bc - _heap_start
    at ??:??
0x00000000 -
    at ??:??
0x3c072e00 - str.0
    at ??:??
0x00000006 - RV_STK_RA
    at ??:??
3fc99ad0: 0x3fc99b64 0x000003e8 0x3c072e00 0x00000006 0x3fc99b64 0x00000001 0x3fc9a100 0x4200ee1c
0x3fc99b64 - _heap_start
    at ??:??
0x000003e8 -
    at ??:??
0x3c072e00 - str.0
    at ??:??
0x00000006 - RV_STK_RA
    at ??:??
0x3fc99b64 - _heap_start
    at ??:??
0x00000001 -
    at ??:??
0x3fc9a100 - _heap_start
    at ??:??
0x4200ee1c - core::option::Option<T>::unwrap
    at /home/al9hu7/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:930
3fc99af0: 0xa5a5a5a5 0x00000001 0x3fc9a100 0x42005856 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
0xa5a5a5a5 - SYSTEM
    at ??:??
0x00000001 -
    at ??:??
0x3fc9a100 - _heap_start
    at ??:??
0x42005856 - <event_listener_strategy::Blocking as event_listener_strategy::Strategy>::wait
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
3fc99b10: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
3fc99b30: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0x3fc8c340 0x3fc9a333 0x00000001 0x00000002
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0x3fc8c340 - _ZN8async_io7reactor7Reactor3get7REACTOR17h9e39ef048be84631E.llvm.5754974393764579329
    at ??:??
0x3fc9a333 - _heap_start
    at ??:??
0x00000001 -
    at ??:??
0x00000002 - EXC_ILLEGAL_INSTRUCTION
    at ??:??
3fc99b50: 0x00000000 0x3fc9a794 0x00000000 0x00000000 0x3fc9a6b0 0x3fc99b48 0x3fc8c340 0x3fc9a333
0x00000000 -
    at ??:??
0x3fc9a794 - _heap_start
    at ??:??
0x00000000 -
    at ??:??
0x00000000 -
    at ??:??
0x3fc9a6b0 - _heap_start
    at ??:??
0x3fc99b48 - _heap_start
    at ??:??
0x3fc8c340 - _ZN8async_io7reactor7Reactor3get7REACTOR17h9e39ef048be84631E.llvm.5754974393764579329
    at ??:??
0x3fc9a333 - _heap_start
    at ??:??
3fc99b70: 0xa5a50001 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
0xa5a50001 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
3fc99b90: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
3fc99bb0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
3fc99bd0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
3fc99bf0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
3fc99c10: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
3fc99c30: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
3fc99c50: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM
    at ??:??
0xa5a5a5a5 - SYSTEM

@ivmarkov
Copy link
Collaborator

It looks like a stack overflow to me...

@teamplayer3
Copy link
Contributor Author

@ivmarkov any thoughts on the points in the init PR comment? I think the sync and async driver combined + address len is pretty neat, but it differs to other driver impls.

@ivmarkov
Copy link
Collaborator

@ivmarkov any thoughts on the points in the init PR comment? I think the sync and async driver combined + address len is pretty neat, but it differs to other driver impls.

Limited access to internet right now. Will follow up when I have an opportunity

@ivmarkov
Copy link
Collaborator

ivmarkov commented May 1, 2024

@teamplayer3 I finally have some time now, so I can start looking into this. My first question would be, why not implementing the new driver in a completely separate module from the old driver? As all "new" drivers were implemented so far (ADC comes to mind)?

The name of the new driver's module is not so important as long as it is separate from the old driver.

Otherwise, we'll lose the old driver completely, and until we have the new driver working properly, we probably don't want this?

@ivmarkov
Copy link
Collaborator

ivmarkov commented May 1, 2024

Ahhhh, you did it except moving the existing driver to legacy.
Maybe (and in the name of backwards compatibility) keep the old driver under its existing i2c module. And then introduce the new driver in a new module? We can always later re-export all pub types from the new driver into the i2c module?

@ivmarkov
Copy link
Collaborator

ivmarkov commented May 1, 2024

Some quick answers here (unfortunately I don't have answers for everything...):

Is it ok to split the drivers into sync and async drivers? Main difference when using async add the isr callback (only one device can be async at a time)

We do both (a single driver and multiple drivers). I'm leaning towards not splitting, as long as it results in readable code and real code reuse. If the async driver uses a completely different code path from the sync driver or it needs some expensive extra state (say, a hidden FreeRtos task to "simulate" async behavior), then it is probably better to keep those separate.

How to support legacy driver (transactional interface) call it LegacyI2cDriver?

As per above, I think we should keep the code base backwards compatible, i.e. the legacy driver for now should stay in place, under its existing name and module.

How to deal with it if two i2c drivers can be used? (must be both legacy or new driver)

No good answer, but we have to support this for other drivers besides i2c. Thinking loud: what if we detect this at runtime, using a global atomic or a mutex? I.e. if the new driver is instantiated on at least one i2c peripheral, the old driver would fail to construct (with a runtime error or a panic)? And the other way around?

support sync and async on one bus? The current implementation allows only sync or async devices.

I think that's good enough.

Use case for setting trans_queue_depth > 1?

No idea :)

How to impl read blocking for I2cSlaveDriver?

No idea, need to look at the C API I guess...

Allow 7/10 bit address (currently in dev config, but embedded_hal needs it within the type itself -> add a generic to the device driver whether it is 7 or 10 bit address)

Yes, a 0-sized type should do.

src/i2c.rs Outdated

let _lock_guard = driver.acquire_bus().await;
enable_master_dev_isr_callback(handle, port)?;
esp!(unsafe {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to mention that this pattern - just like the same pattern in the SPI async code - is actually unsafe in the presence of core::mem::forget

Imagine that you have called write(...).await, the buf is passed to the C driver, but then you core::mem::forget the future returned by the write method. What would happen, is that the C driver would still use your reference to buf - yet - from the point of view of Rust, the reference is no longer in use (because you just forgot the future!) - hence - it will allow you to do whatever you want with the buf.

Unfortunately I don't have a great solution. Easiest is to mark the write method (and all its friends) with unsafe, as not core::mem::forget-ing the future is something that the user now has to obey, and it is not captured in the rust type system.

The problem is, the write method on the e-hal is however NOT marked with unsafe...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is not clear, the real solution is owned buffers. In other words, the Rust driver itself should first copy the data into its own owned buffers, and pass references to the C drivers to its own buffers.
This comes with disadvantages though - as in - extra memory use, extra copying...

src/i2c.rs Outdated
esp!(unsafe {
i2c_master_transmit_receive(
handle,
bytes.as_ptr().cast(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto, as per above.

src/i2c.rs Outdated
esp!(unsafe {
i2c_master_receive(
handle,
buffer.as_mut_ptr().cast(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See below.

src/i2c.rs Outdated
})?;

NOTIFIER[port as usize].wait().await;
disable_master_dev_isr_callback(handle)?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would never be called if i2c_master_receive returns an error. You probably don't want this?

src/i2c.rs Outdated
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
I2cDriver::write(self, addr, bytes, BLOCK).map_err(to_i2c_err)
#[cfg(not(esp_idf_i2c_isr_iram_safe))]
pub struct OwnedAsyncI2cDeviceDriver<'d> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate why we need the Owned version of the driver? Not clear to me...

Also, thinking loud, but to your earlier question of whether we need separate sync and async versions of the driver... my feeling is that it might be easier for that dirver particularly, if it is a single driver, with read_async / write_async, *_async extra methods...?

src/i2c.rs Outdated
})?;

NOTIFIER[port as usize].wait().await;
disable_master_dev_isr_callback(handle)?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a bit unclear to me from the ESP IDF docs whether the transmit function can still return with ESP_ERR_TIMEOUT when you have the callback registered? Maybe we need to examine the source code?

Because if that's the case, then we need a more complex logic here, potentially involving a loop?

src/i2c.rs Outdated

#[cfg(not(esp32c2))]
unsafe impl<'d> Send for I2cSlaveDriver<'d> {}
todo!("How to block?");
Copy link
Collaborator

@ivmarkov ivmarkov May 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Roughly speaking (there are more details to this):
You need a blocking mutex and a condvar. You need to lock the blocking mutex and then wait on the condvar. Waiting on the condvar will temporarily unlock the mutex. In the callback handler, besides notifying the static async notification, you also need to lock the mutex and then notify the condvar.

@teamplayer3
Copy link
Contributor Author

As per above, I think we should keep the code base backwards compatible, i.e. the legacy driver for now should stay in place, under its existing name and module.

As soon functions are linked in from both driver versions, an error is thrown at startup:

E (382) i2c: CONFLICT! driver_ng is not allowed to be used with this old driver

This because of a check in i2c.c: check_i2c_driver_conflict

This means we cannot use both drivers simultaneous.

@ivmarkov
Copy link
Collaborator

ivmarkov commented Jun 6, 2024

As per above, I think we should keep the code base backwards compatible, i.e. the legacy driver for now should stay in place, under its existing name and module.

As soon functions are linked in from both driver versions, an error is thrown at startup:

E (382) i2c: CONFLICT! driver_ng is not allowed to be used with this old driver

This because of a check in i2c.c: check_i2c_driver_conflict

This means we cannot use both drivers simultaneous.

I see.

Deleting the legacy driver is still not an option. At least not until (a) the new driver is proven reliable (b) the old ESP IDF 5 versions are no longer used. (Because the new driver was introduced after ESP IDF 5.0, right?)

Is the new driver (and the old driver) somehow covered by an ESP IDF component? Or is there a CONF_ setting whether to use one or the other? If any of these is true, then we can explore this path.

As much as I hate it, in the absence of one of the two options from above, we can introduce a feature for that then. Something like legacy_i2c. It will be on by default, and thus will only allow the legacy driver. If users want to use the new driver, they'll have to run with default-features=false. And once the new driver is stabilized, we can remove the legacy_i2c feature.

But let's first carefully check if we have a CONF_ or if one (or both) of the drivers are in fact in separate components?

@ivmarkov
Copy link
Collaborator

ivmarkov commented Jun 6, 2024

Actually...

The above will happen ONLY if the code of the user is calling into BOTH drivers!
If the user is not using both drivers, there should be no problem? Right?
Hint: Rust only links code that you call into. The rest is pruned.

@teamplayer3
Copy link
Contributor Author

Problem with embedded_hal impl of transaction() interface (not implemented in new driver interface): This could be implemented with i2c_jobs but as stated this wouldn't come soon. issue comment

@teamplayer3
Copy link
Contributor Author

Actually...

The above will happen ONLY if the code of the user is calling into BOTH drivers!
If the user is not using both drivers, there should be no problem? Right?
Hint: Rust only links code that you call into. The rest is pruned.

If I remove the legacy mod from i2c, it works without a problem. If I only use the new driver in my main code, and don't have removed the legacy stuff in esp-idf-hal, the error mentioned occurs.

@ivmarkov
Copy link
Collaborator

ivmarkov commented Jun 6, 2024

Actually...

The above will happen ONLY if the code of the user is calling into BOTH drivers!
If the user is not using both drivers, there should be no problem? Right?
Hint: Rust only links code that you call into. The rest is pruned.

If I remove the legacy mod from i2c, it works without a problem. If I only use the new driver in my main code, and don't have removed the legacy stuff in esp-idf-hal, the error mentioned occurs.

This does not sound right. This means something is calling into the legacy code. Or the linker is not pruning the legacy code, which would also be weird.

@Vollbrecht
Copy link
Collaborator

Vollbrecht commented Jun 6, 2024

Actually...

The above will happen ONLY if the code of the user is calling into BOTH drivers! If the user is not using both drivers, there should be no problem? Right? Hint: Rust only links code that you call into. The rest is pruned.

That all sounds nice in theory but in practice we run over and over into the problem with all legacy drivers. The simple truth is that esp-idf forbid the usage of both at the same time while not providing a compile time solution to exclusively select a driver.

The pain point is that in our compiled libespidf.elf we always have both symbols for new and old drivers, something that would not so easily happen in a pure C project since you only use the header you need.

We discussed the point some time ago a bit, but my stance is that we still should try find a way ( for example with more exclusive imports of old and new drivers in the bindgen.h) to make a more clear cut at the root of the issue and not engineer around it by shifting the problem into manual labor - tripple check if anything aligns correctly with all our drivers so we don't accidental call into old or new api where we should not,

@teamplayer3
Copy link
Contributor Author

teamplayer3 commented Jun 6, 2024

Actually...

The above will happen ONLY if the code of the user is calling into BOTH drivers!
If the user is not using both drivers, there should be no problem? Right?
Hint: Rust only links code that you call into. The rest is pruned.

If I remove the legacy mod from i2c, it works without a problem. If I only use the new driver in my main code, and don't have removed the legacy stuff in esp-idf-hal, the error mentioned occurs.

This does not sound right. This means something is calling into the legacy code. Or the linker is not pruning the legacy code, which would also be weird.

Tests:

  1. mod legacy and new driver in esp-idf-hal
    • don't remove any driver in esp-idf-hal
    • use only one driver of them (either legacy or new) in main code
    • error is thrown at startup
  2. remove the other impl in esp-idf-hal
    • use only one driver of them (either legacy or new) in main code
    • remove other impl
    • no error

This check is done in this function:

__attribute__((constructor))
static void check_i2c_driver_conflict(void)
{
    // This function was declared as weak here. The new I2C driver has the implementation.
    // So if the new I2C driver is not linked in, then `i2c_acquire_bus_handle()` should be NULL at runtime.
    extern __attribute__((weak)) esp_err_t i2c_acquire_bus_handle(int port_num, void *i2c_new_bus, int mode);
    if ((void *)i2c_acquire_bus_handle != NULL) {
        ESP_EARLY_LOGE(I2C_TAG, "CONFLICT! driver_ng is not allowed to be used with this old driver");
        abort();
    }
    ESP_EARLY_LOGW(I2C_TAG, "This driver is an old driver, please migrate your application code to adapt `driver/i2c_master.h`");
}

@Vollbrecht
Copy link
Collaborator

Vollbrecht commented Jun 6, 2024

I think one solution could look like the following: us providing "user defined" kconfigs that define appropriate compiletime flags. That flags can be consumed in the binding.h and would also automatically generate them as to rust cfg(). A normal user than could set them in their sdkconfig file selecting old or new, with one of them as the default.

That would need some work on us providing the mechanism in the first place in the current embuild/esp-idf-sys dynamic but i think its not to far out. I can explore it if you think that would be a viable solution.

@teamplayer3
Copy link
Contributor Author

I think one solution could look like the following: us providing "user defined" kconfigs that define appropriate compiletime flags. That flags can be consumed in the binding.h and would also automatically generate them as to rust cfg(). A normal user than could set them in their sdkconfig file selecting old or new, with one of them as the default.

That would need some work on us providing the mechanism in the first place in the current embuild/esp-idf-sys dynamic but i think its not to far out. I can explore it if you think that would be a viable solution.

This would be a nice thing solution which will align to the esp-idf config.

I think a quick solution to switch to the legacy version would be to add a feature to esp-idf-hal, something like driver-i2c-legacy. If it isn't set, the new one is used and if it is set the legacy one is used. But of course, then all drivers are included in esp-idf-sys and it would not fix the root cause.

@ivmarkov
Copy link
Collaborator

ivmarkov commented Jun 6, 2024

@teamplayer3 - thanks for you analysis, but this is not complete yet? It is unpleasant - I can imagine - but I would go inspect the .elf file and try to understand, why is a bunch of code ending up in there when it shouldn't. Or try to understand how exactly _attribute((constructor))__ works in GCC. Because it really shouldn't be as you describe - if you don't use the code from an .o file, it is not getting linked. There is something we don't understand still.

@Vollbrecht Not even sure where to start? Maybe these two comments:

The pain point is that in our compiled libespidf.elf we always have both symbols for new and old drivers,

It is not .elf but .a. The fact that we have both symbols for old and new drivers there is not a problem in my opinion. Please explain why this is a problem. Also if you can explain why the fact that we have both new and old i2c symbols in the libespidf.a file is not a problem even here, as long as @teamplayer3 comments out the Rust code (which is weird!).

something that would not so easily happen in a pure C project since you only use the header you need.

Headers have nothing to do with what symbols you end up with in your .o file. I can #include "internet.h" - yet - if I am not calling the internet, I'll not end up with any __internet symbols in my .o file.

==============

Please don't take the above as nit-picking. Really! The last thing I want is to demotivate folks by pointing at their (potential) mistakes.

BUT: I'm absolutely NOT OK with introducing grandiose new solutions (like the user-defined "conf" thing) or even new features to problems that we still do not understand completely.

@ivmarkov
Copy link
Collaborator

ivmarkov commented Jun 8, 2024

  1. mod legacy and new driver in esp-idf-hal

    • don't remove any driver in esp-idf-hal
    • use only one driver of them (either legacy or new) in main code
    • error is thrown at startup
  2. remove the other impl in esp-idf-hal

    • use only one driver of them (either legacy or new) in main code
    • remove other impl
    • no error

@Vollbrecht @teamplayer3 I think I have a very good hypothesis for the above problem that needs a quick test:
What happens, if you put the legacy driver module, and the new driver module into two separate .rs files?

I'm betting and hoping that the problem will then disappear!

Background: https://rustc-dev-guide.rust-lang.org/backend/libs-and-metadata.html

Specifically the section which says:
"
Object code, which is the result of code generation. This is used during regular linking. There is a separate .o file for each codegen unit.
"

(... where codegen unit = one .rs file, even if it contains 20 mods inside). I.e. since we have just one .rs file for both legacy and new driver, we end up with a single .o file.
Further since I'm not sure that the linker properly uses "function-level lLTO" (though I swear I noticed this option in the linker cmd args!), the linker will link-in to the final ELF both the old and the new rmt driver wrappers (and thus both the old and the new ESP IDF C rmt drivers), as long as we are calling even just one of them.

@ivmarkov
Copy link
Collaborator

ivmarkov commented Jun 8, 2024

Unfortunately, it might not be as simple as I thought.

To translate the above ^^^ in simple terms, it seems there is just no .rs <-> .o file 1:1 mapping, as it is in the C world.
An ar x ../libesp_idf_hal-db4db3c07b0be074.rlib (.rlib is what is produced for a library crate; for us, this is really an .a artchive, just like in the C world) gives me this:

-rw-r--r-- 1 ivan ivan     9524 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.11y7qvjw0q7jfysm.rcgu.o
-rw-r--r-- 1 ivan ivan     2892 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.138ce0mwti3535vo.rcgu.o
-rw-r--r-- 1 ivan ivan     5688 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.13frxtu2cpg0k421.rcgu.o
-rw-r--r-- 1 ivan ivan     4056 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.18q0z3o3zrpc9qlw.rcgu.o
-rw-r--r-- 1 ivan ivan     4912 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.18zwgqsy9f7zc7av.rcgu.o
-rw-r--r-- 1 ivan ivan     7248 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.1bwbpcqcj34ajdr8.rcgu.o
-rw-r--r-- 1 ivan ivan    29712 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.1g2o5pdbdymhsn16.rcgu.o
-rw-r--r-- 1 ivan ivan     5068 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.1kooln3tjfbcq6x1.rcgu.o
-rw-r--r-- 1 ivan ivan    17640 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.1ooo88p80vjirj0c.rcgu.o
-rw-r--r-- 1 ivan ivan    33656 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.1zzd6fyf7r4c2260.rcgu.o
-rw-r--r-- 1 ivan ivan   148816 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.21fi11wdsi0xv7js.rcgu.o
-rw-r--r-- 1 ivan ivan    12552 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.2507ereh8du1e7nx.rcgu.o
-rw-r--r-- 1 ivan ivan    43580 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.29k29lbshqczqcwo.rcgu.o
-rw-r--r-- 1 ivan ivan    16904 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.29vv917wu80y28pi.rcgu.o
-rw-r--r-- 1 ivan ivan     5360 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.2bacrwh83v8e2t5e.rcgu.o
-rw-r--r-- 1 ivan ivan     4556 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.2d0i8tbf8qbfiyq1.rcgu.o
-rw-r--r-- 1 ivan ivan    29584 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.2dsofw23t9c16d7k.rcgu.o
-rw-r--r-- 1 ivan ivan    14828 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.2g81urk54ove8e1s.rcgu.o
-rw-r--r-- 1 ivan ivan    23892 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.2mlnc0fe2nfl5zuy.rcgu.o
-rw-r--r-- 1 ivan ivan     5436 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.2r1qz0d9x0wd0fre.rcgu.o
-rw-r--r-- 1 ivan ivan     4556 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.2v926gdbqywlg5rf.rcgu.o
-rw-r--r-- 1 ivan ivan     9172 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.2vgxm90jvp3nvdd0.rcgu.o
-rw-r--r-- 1 ivan ivan    61252 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.30d50ndwffbn5pkq.rcgu.o
-rw-r--r-- 1 ivan ivan    12152 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.372eeh6qxyou9gp2.rcgu.o
-rw-r--r-- 1 ivan ivan    15340 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.3a1rjqenohxk5agw.rcgu.o
-rw-r--r-- 1 ivan ivan    78764 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.3a50tdvnyxtcc3tk.rcgu.o
-rw-r--r-- 1 ivan ivan     3820 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.3l2hem2d5m8ac04s.rcgu.o
-rw-r--r-- 1 ivan ivan     3768 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.3p1tzkjvizkc6haj.rcgu.o
-rw-r--r-- 1 ivan ivan     9352 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.3r1dddvi39cp5ao0.rcgu.o
-rw-r--r-- 1 ivan ivan     5432 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.3rxvc436cg6macyf.rcgu.o
-rw-r--r-- 1 ivan ivan     2796 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.3ua9an8otuzkowo8.rcgu.o
-rw-r--r-- 1 ivan ivan    15664 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.3usnspq80sb3lrji.rcgu.o
-rw-r--r-- 1 ivan ivan   105568 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.3vhnaab2k2160ikr.rcgu.o
-rw-r--r-- 1 ivan ivan     9852 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.3ylsu9r96xrbl3ov.rcgu.o
-rw-r--r-- 1 ivan ivan    19684 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.43h7njhetdxtzgxj.rcgu.o
-rw-r--r-- 1 ivan ivan    11116 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.46fzkqwc4245mftm.rcgu.o
-rw-r--r-- 1 ivan ivan    25608 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.4e8cs81nax0n01k7.rcgu.o
-rw-r--r-- 1 ivan ivan     4336 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.4fpscyl2056f7176.rcgu.o
-rw-r--r-- 1 ivan ivan     3560 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.4gi1q0jjrea8qvyw.rcgu.o
-rw-r--r-- 1 ivan ivan     8400 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.4h7w5m444jeptotj.rcgu.o
-rw-r--r-- 1 ivan ivan     8764 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.4ii677slggyoo940.rcgu.o
-rw-r--r-- 1 ivan ivan     3676 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.4jwpcbz6cg5mzht2.rcgu.o
-rw-r--r-- 1 ivan ivan    95780 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.4u57ayox9ot5quqw.rcgu.o
-rw-r--r-- 1 ivan ivan     4936 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.4xb1t2i9p8qqcxdc.rcgu.o
-rw-r--r-- 1 ivan ivan    22508 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.4yvo6ufzlntlqddh.rcgu.o
-rw-r--r-- 1 ivan ivan    20956 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.50o5553cvx6vyffp.rcgu.o
-rw-r--r-- 1 ivan ivan    11416 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.50ou3t5efwv3o7f0.rcgu.o
-rw-r--r-- 1 ivan ivan   105196 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.52obe496vpc81dpi.rcgu.o
-rw-r--r-- 1 ivan ivan    54636 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.545s7o5a9yyoeidj.rcgu.o
-rw-r--r-- 1 ivan ivan     9756 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.54tjwmop61rkramc.rcgu.o
-rw-r--r-- 1 ivan ivan    23980 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.56w5kb514jfdvxen.rcgu.o
-rw-r--r-- 1 ivan ivan    86208 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.58g57hbq2evt61pz.rcgu.o
-rw-r--r-- 1 ivan ivan    51412 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.590nsxugwp8etfx1.rcgu.o
-rw-r--r-- 1 ivan ivan    10324 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.596s8actvkgarobp.rcgu.o
-rw-r--r-- 1 ivan ivan    47516 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.5at9q0n3gqliys5j.rcgu.o
-rw-r--r-- 1 ivan ivan    82432 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.5avlu5x3nglpel6n.rcgu.o
-rw-r--r-- 1 ivan ivan     5788 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.5c028wdl42q9e1sr.rcgu.o
-rw-r--r-- 1 ivan ivan    27304 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.85kmorrcn46kd46.rcgu.o
-rw-r--r-- 1 ivan ivan     7392 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.b3xdtbxb6wpc07h.rcgu.o
-rw-r--r-- 1 ivan ivan     3484 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.dkrytxaryd89mqn.rcgu.o
-rw-r--r-- 1 ivan ivan    25604 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.jhgjkomrtw08wr5.rcgu.o
-rw-r--r-- 1 ivan ivan    33864 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.mkwk0ds84hxsacd.rcgu.o
-rw-r--r-- 1 ivan ivan     2840 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.n91x7pos5pvll77.rcgu.o
-rw-r--r-- 1 ivan ivan    40268 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.rn9c0f476qhonci.rcgu.o
-rw-r--r-- 1 ivan ivan   119652 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.sdoxwm2b5pdka8e.rcgu.o
-rw-r--r-- 1 ivan ivan    17000 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.tatc5rbjlkksssf.rcgu.o
-rw-r--r-- 1 ivan ivan    25688 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.ufoyuyc7ssc6cr5.rcgu.o
-rw-r--r-- 1 ivan ivan     7920 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.upzeisz2crfv2ne.rcgu.o
-rw-r--r-- 1 ivan ivan     8412 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.v7pd67b1o1axfxx.rcgu.o
-rw-r--r-- 1 ivan ivan   182200 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.v7rfpx8em8zol4z.rcgu.o
-rw-r--r-- 1 ivan ivan    11400 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.vbzu99cs6kknwqw.rcgu.o
-rw-r--r-- 1 ivan ivan     5856 Jun  8 13:57 esp_idf_hal-db4db3c07b0be074.vp71jqnz7q7umod.rcgu.o

Now, these .os might correspond to the .rs files in esp-idf-hal, but I cannot really be sure.
What that means - in the worst case - is that - whatever we do - the old and the new RMT driver might still end up in the same .o file and thus - in the absence of function-level LTO - we'll end up with the CONFLICT! issue again.

@ivmarkov
Copy link
Collaborator

ivmarkov commented Jun 8, 2024

@teamplayer3 You are using xtensa or riscv MCU for your tests?

@teamplayer3
Copy link
Contributor Author

You are using xtensa or riscv MCU for your tests?

@ivmarkov for tests I used riscv

@ivmarkov
Copy link
Collaborator

ivmarkov commented Jun 8, 2024

@teamplayer3 if you can do one more test whenever you have some time, sorry: can you compile in release and see if you are still reproducing the problem?

@Vollbrecht
Copy link
Collaborator

@ivmarkov here is a minimal repo that reproduces the error. It only has a lib.rs that has two function, one using the legacy driver and one using the new one. In the bin.rs only the new one is called but it fails at runtime with the usual error.

@Vollbrecht
Copy link
Collaborator

my example fails for me both with cargo r and cargo r --release

@ivmarkov
Copy link
Collaborator

esp-rs/esp-idf-sys#313

@kaaax0815
Copy link

Whats the status on this?

@ivmarkov
Copy link
Collaborator

Whats the status on this?

The root cause prohibiting the merge of the driver is solved, yet there is still feedback in the driver code itself that needs to be addressed. For one, I would appreciate if the old (4.4.X) driver is left untouched as much as possible (including in its current module as well as its location in the file), and the new 5.X driver is in its own sub-module. For one, that would make the review much easier as the current diff is very difficult to review.

There were other issues as far as I remember, but the bottom line is somebody needs to volunteer and pick it up. The esp-idf-* crates are a community effort so unless somebody puts some effort here, it would stay as-is.

@teamplayer3
Copy link
Contributor Author

I can pick it up again. And see if I can make it more diff friendly. @kaaax0815 maybe you can test it, because I'm missing the test infrastructure currently.

@ivmarkov
Copy link
Collaborator

ivmarkov commented Dec 20, 2024

I can pick it up again. And see if I can make it more diff friendly. @kaaax0815 maybe you can test it, because I'm missing the test infrastructure currently.

@teamplayer3 Just to mention that when saying that the root cause is solved, this unfortunately does not mean it is solved at the ESP-IDF level.

We do need to introduce a feature toggle for switching between the legacy and the new driver similar to this one. But at least now we know why this is necessary in the first place (because of those pesky GCC C constructor functions that get pulled-in if we have any code compiled and referencing the legacy or the new driver - even if that code is pruned by the linker the GCC C constructors that were pulled by the pruned code would stay and be called).

So if that means the legacy code needs to be surrounded with a mod i2c_legacy { ... } module, than fine, be it, let's just leave it where it is physically, so that diff can do a better job at figuring out the actual differences. :-)

@kaaax0815
Copy link

I don't know if I'll be able to test this. As I am using Wokwi currently. And maybe the components I want to use use spi

@teamplayer3
Copy link
Contributor Author

Currently, I have problems building the hal. These are the same problems why esp-idf-template not building in CI. How can I fix these? I want to build for riscv by using rust nightly.

Compile Error:
error[E0308]: mismatched types
    --> /home/al9hu7/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/pal/unix/fs.rs:1053:33
     |
1053 |         unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
     |                  -------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `*const u8`, found `*const i8`
     |                  |
     |                  arguments to this function are incorrect
     |
     = note: expected raw pointer `*const u8`
                found raw pointer `*const i8`
note: associated function defined here
    --> /home/al9hu7/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ffi/c_str.rs:276:25
     |
276  |     pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
     |                         ^^^^^^^^

error[E0308]: mismatched types
    --> /home/al9hu7/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/pal/unix/fs.rs:1185:43
     |
1185 |         let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?;
     |                                    ------ ^^^^^^^^^^^^^ expected `*const i8`, found `*const u8`
     |                                    |
     |                                    arguments to this function are incorrect
     |
     = note: expected raw pointer `*const i8`
                found raw pointer `*const u8`
note: function defined here
    --> /home/al9hu7/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/libc-0.2.168/src/unix/mod.rs:851:12
     |
851  |     pub fn open(path: *const c_char, oflag: c_int, ...) -> c_int;
     |            ^^^^

error[E0308]: mismatched types
    --> /home/al9hu7/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/pal/unix/fs.rs:1555:61
     |
1555 |         run_path_with_cstr(p, &|p| cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) }).map(|_| ()))
     |                                                 ----------- ^^^^^^^^^^ expected `*const i8`, found `*const u8`
     |                                                 |
     |                                                 arguments to this function are incorrect
     |
     = note: expected raw pointer `*const i8`
                found raw pointer `*const u8`

@Vollbrecht
Copy link
Collaborator

Currently, I have problems building the hal. These are the same problems why esp-idf-template not building in CI. How can I fix these? I want to build for riscv by using rust nightly.

Upstream broke all nightly versions, because they changed c_char definition stuff. A patch to fix it for esp-idf should be already merged but we need to wait so it trickels down...

@kaaax0815
Copy link

i fixed it temporarily by using esp channel

@teamplayer3
Copy link
Contributor Author

For now, I restricted the AsyncDeviceDriver to only one async device per bus, as documented in docs. If another one is constructed, a runtime error will be returned. (tried to determine the cause of this by the source code - couldn't find the reason. Maybe I overlooked something, but the callback is set per device.)

As I understand it, this applies to the callback function, which is called after completed transactions and must be set for a device which should support async operations. In other words, you could remove this restriction if the callback is reset for each transaction (read, write, writeRead) and the bus is blocked for asynchronous transactions by semaphore or mutex. But I'm not quite sure, it must be tested.

start async trans
- lock bus for async
- set callback
- write/read/write&read
- wait on done
- reset callback
- unlock bus for async
end async trans

This would lead to the next async transaction call gets blocked until the last is finished. I think this is completely fine as long the blocking mechanism is async.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support async in i2c Driver by using new ESP-IDF V5.2 driver impl
4 participants