Open TheZoq2 opened 7 years ago
Hey @TheZoq2, check out the contents of teensy3-rs-demo/target/thumb.../release/build/teensy3-sys-.../out/bindings.rs
. This is where the generated bindings get put.
You'll see something like this:
#[repr(C)]
pub struct TwoWire {
pub _base: Stream,
pub __bindgen_anon_1: TwoWire_I2C_Hardware_t,
pub port: *mut KINETIS_I2C_t,
pub hardware: *const TwoWire_I2C_Hardware_t,
pub rxBuffer: [u8; 32usize],
pub rxBufferIndex: u8,
pub rxBufferLength: u8,
pub txAddress: u8,
pub txBuffer: [u8; 33usize],
pub txBufferIndex: u8,
pub txBufferLength: u8,
pub transmitting: u8,
pub slave_mode: u8,
pub irqcount: u8,
pub sda_pin_index: u8,
pub scl_pin_index: u8,
pub user_onRequest: ::core::option::Option<unsafe extern "C" fn()>,
pub user_onReceive: ::core::option::Option<unsafe extern "C" fn(arg1:
c_types::c_int)>,
}
// ...
impl TwoWire {
#[inline]
pub unsafe fn begin(&mut self) { TwoWire_begin(self) }
#[inline]
pub unsafe fn begin1(&mut self, address: u8) {
TwoWire_begin1(self, address)
}
#[inline]
pub unsafe fn begin2(&mut self, address: c_types::c_int) {
TwoWire_begin2(self, address)
}
// ...
#[inline]
pub unsafe fn new(myport: *mut KINETIS_I2C_t,
myhardware: *const TwoWire_I2C_Hardware_t) -> Self {
let mut __bindgen_tmp = ::core::mem::uninitialized();
TwoWire_TwoWire(&mut __bindgen_tmp, myport, myhardware);
__bindgen_tmp
}
}
Based on this, I think you will need something like this:
unsafe {
// you need to replace the "..." here with something
let mut i = bindings::KINETIS_I2C_t{ ... };
let mut hw = bindings::TwoWire_I2C_Hardware_t{ ... };
// something like this, not 100% sure about the syntax here
let mut x = bindings::TwoWire::new(&mut i, &mut hw);
x.begin();
// ...
}
Let me know if this helps.
Also to clarify, in the Arduino environment, they create an instance of the TwoWire class "implicitly". I just looked at the source, and I saw this in WireKinetis.cpp:778
:
#ifdef WIRE_IMPLEMENT_WIRE // This is set for the Teensy 3.x family
TwoWire Wire(KINETIS_I2C0, TwoWire::i2c0_hardware);
void i2c0_isr(void) { Wire.isr(); }
#endif
This means that the C++ class is creating an instance of TwoWire
named Wire
. I honestly have no idea how to access it. In C, I would do something like this:
extern TwoWire Wire;
// ...
Wire.begin();
I'm not sure how to do that in Rust (if it is possible). If you can't find a way to do it, you can follow my instructions in the message above on how to create a new instance of TwoWire in rust. The C++ code is helpful to tell you what to put in those { ... }
s I mentioned above:
#define KINETIS_I2C0 (*(KINETIS_I2C_t *)0x40066000)
const TwoWire::I2C_Hardware_t TwoWire::i2c0_hardware = {
SIM_SCGC4, SIM_SCGC4_I2C0,
#if defined(__MKL26Z64__) || defined(__MK20DX128__) || defined(__MK20DX256__)
18, 17, 255, 255, 255,
2, 2, 0, 0, 0,
19, 16, 255, 255, 255,
2, 2, 0, 0, 0,
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__)
18, 17, 34, 8, 48,
2, 2, 5, 7, 2,
19, 16, 33, 7, 47,
2, 2, 5, 7, 2,
#endif
IRQ_I2C0
};
Oh. Derp. From bindings.rs
:
extern "C" {
#[link_name = "Wire"]
pub static mut Wire: TwoWire;
}
That would do it. Try this:
pub fn begin_master()
{
unsafe {
bindings::Wire.begin();
}
}
Okay. I've come full circle. I think I now understand your actual question. I've also decided to stop answering questions at 1am.
I don't know why the linker is having an issue with a missing Wire1
. For every target other than TeensyLC
, it should exist. Something (gcc?) is probably stripping the symbol out, since it thinks it is unused. There are a couple fixes for that, but I would have to test them.
I still think making a new instance as I described above would work, but probably shouldn't be necessary. I will shut up now until I have time to actually test my suggestions locally. Sorry for blowing up your inbox with notifications. Hopefully some of this actually helped, and I wasn't just telling you things you already know :)
I don't know why the linker is having an issue with a missing Wire1. For every target other than TeensyLC, it should exist. Something (gcc?) is probably stripping the symbol out, since it thinks it is unused. There are a couple fixes for that, but I would have to test them
Yep, GCC stripping them out sounds like a pretty good theory. Also, it's not just Wire1
, Wire
and Wire2
don't work either.
I still think making a new instance as I described above would work, but probably shouldn't be necessary.
I'll look into that and see if I can figure it out.
Sorry for blowing up your inbox with notifications. Hopefully some of this actually helped, and I wasn't just telling you things you already know :)
No worries about the spam, it gave me some ideas about things to try. Though you could always edit the message if you think people are annoyed by the spam :P
Edit: I'm not sure how to properly initialize the two_wire class. Specifically, i'm not sure how to set the _base member.
I did some more thinking and testing about this and I'm not sure if the issue is with the Wire constants.
Wouldn't the linker complain about TwoWire::begin
and not just begin
if that was the case? Or is rust/bindgen doing some magic in the background?
Also, I noticed that the SPI functions in the crate have the same issue.
let spi = teensy3::spi::Spi{};
spi.begin();
I also tested
unsafe {
bindings::SPIClass_begin();
}
Which gives the same error:
= note: "arm-none-eabi-gcc" "-L" "/home/frans/.xargo/lib/rustlib/thumbv7em-none-eabihf/lib" "/home/frans/Documents/rust/teensy/playground/target/thumbv7em-none-eabihf/debug/deps/teensy3_rs_demo-a6c1a5face9da051.0.o" "-o" "/home/frans/Documents/rust/teensy/playground/target/thumbv7em-none-eabihf/debug/deps/teensy3_rs_demo-a6c1a5face9da051" "-Wl,--gc-sections" "-nodefaultlibs" "-L" "/home/frans/Documents/rust/teensy/playground/target/thumbv7em-none-eabihf/debug/deps" "-L" "/home/frans/Documents/rust/teensy/playground/target/debug/deps" "-L" "/home/frans/Documents/rust/teensy/playground/target/thumbv7em-none-eabihf/debug/build/teensy3-sys-f07c06b4a4fe31a2/out" "-L" "/home/frans/Documents/rust/teensy/playground/target/thumbv7em-none-eabihf/debug/build/teensy3-sys-f07c06b4a4fe31a2/out" "-L" "/home/frans/.xargo/lib/rustlib/thumbv7em-none-eabihf/lib" "-Wl,-Bstatic" "/tmp/rustc.V97TmF8YLyZW/libteensy3_sys-c0adf1102c30f343.rlib" "-Tteensy3-sys.ld" "-Wl,--gc-sections,--defsym=__rtc_localtime=0" "-Wl,--start-group" "-Wl,--end-group" "-lm" "-lnosys" "-lc" "-lgcc" "-mcpu=cortex-m4" "-mthumb" "-Os" "--specs=nano.specs" "-mfloat-abi=hard" "-mfpu=fpv4-sp-d16" "-Wl,-Bdynamic"
= note: /home/frans/Documents/rust/teensy/playground/target/thumbv7em-none-eabihf/debug/deps/teensy3_rs_demo-a6c1a5face9da051.0.o: In function `teensy3_rs_demo::main':
/home/frans/Documents/rust/teensy/playground/src/main.rs:63: undefined reference to `begin'
collect2: error: ld returned 1 exit status
In the bindings.rs file it seems like bindgen generates functions for all methods of a class and prefixes them with ClassName_
but it also puts [#link_name = "..."]
before it
extern "C" {
#[link_name = "begin"]
pub fn SPI2Class_begin();
}
To me, the link_name = "begin"
thing would cause the undefined reference to begin
error since the linker looks for begin
instead of SpiClass::begin()
. Could this be a bindgen issue?
@TheZoq2 Did you ever get further along with this? I'm attempting to integrate OctoWS2811 and having very similar problems
I did not, I lost interest in using rust on teensys for a while and then started using it on a "blue pill" board instead
On Fri, 11 May 2018, 22:44 Patrick Brown, notifications@github.com wrote:
@TheZoq2 https://github.com/TheZoq2 Did you ever get further along with this? I'm attempting to integrate OctoWS2811 and having very similar problems
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/jamesmunns/teensy3-rs/issues/22#issuecomment-388480731, or mute the thread https://github.com/notifications/unsubscribe-auth/AFERLaEyfg9TpXpAKURKhOl9LFPa7WH7ks5txfhGgaJpZM4NKfou .
Alright, thanks for the response!
I am trying to use get i2c communication to work but i'm getting a linker error when I use any of the functions.
In the compiled documentation, I have found the struct
teensy3_sys::TwoWire
which I assume is generated from the arduinoTwoWire
class defined inhardware/teensy/avr/Wire
orhardware/arduino/avr/libraries/Wire/
I have also found
bindings::Wire
,bindings::Wire1
andbindings::Wire2
. They all have the following type signatureI assume they are the same instances of TwoWire you use in regular arduino code.
Because of this, I assume that the following code should compile and work fine
However, if I add a call to
begin_master
to my main program, I get the following linker error:I also tried
bindings::TwoWire_begin(&mut bindings::Wire1);
which gives me the same error.Looking at the arduino source, I don't see why there would be a function called
begin
, if anythign it should beTwoWire::begin
. I also don't see bindings for the internal c code that TwoWire wraps aroundlibraries/Wire/src/utility/twi.c
.This is when trying to compile for teensy3.5, I have not tried 3.2