-
Notifications
You must be signed in to change notification settings - Fork 182
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
tib888 can impl #101
tib888 can impl #101
Conversation
I don't have any experience with CAN buses, so I can't comment much on it unfortunately |
It was a working and almost complete implementation. However it doesn't implement the embedded-hal CAN abstraction yet... |
IIRC, an embedded-hal CAN abstraction is considered out of scope for that project.
Was as in "it's not working anymore" or "it hasn't been tested recently"? If it's the latter and one or two people with experience of CAN buses can comment on this, I wouldn't mind merging it :) |
Any ideas how to test it? It loosk like CAN is a real problem in embedded hal, it's not done after 3 attempts. So maybe it's better to have some implementation, then another and then conclude interface to embedded hal? |
Yea, sounds reasonable. The testing doesn't really have be thorough, just some indication that it does roughly what's expected :P So if you use it for something, let us know how it works |
|
@TheZoq2 Thing is with lack of docs and examples it's kinda hard to write an example. |
Yea, lack of examples and docs certainly makes it harder, perhaps @tib888 could help answer some questions. You probably first want to rebase this PR onto the current master, hopefully that should happen without conflicts. git clone [email protected]:burrbull/stm32f1xx-hal.git
cd stm32f1xx-hal
git remote add upstream [email protected]:stm32/stm32f1xx-hal.git
git rebase upstream/master Then you can add that version of the crate to your project using [dependencies.stm32f1xx_hal]
path = "path/to/stm32f1xx-hal |
I've rebased, so now it should work with [dependencies.stm32f1xx_hal]
git = "https://github.com/burrbull/stm32f1xx-hal"
branch = "can2" |
anyone got demo app working? Or something like test app? |
Well there is one example beside my original implementation: Unfortunately I do not have time to deal with this, but I plan revisit this in a few months. |
Little corrections [dependencies.stm32f1xx-hal]
features = ["rt", "stm32f103", "medium"]
git = "https://github.com/burrbull/stm32f1xx-hal"
branch = "can2" Also, we have a problem with compilation with error like: >cargo build
Compiling stm32f1xx-hal v0.5.3 (https://github.com/burrbull/stm32f1xx-hal?branch=can2#36dbdabc)
error[E0624]: method `mapr` is private
--> .cargo\git\checkouts\stm32f1xx-hal-bc72ae77c0f80995\36dbdab\src\can.rs:351:14
|
351 | mapr.mapr()
| ^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0624`.
error: could not compile `stm32f1xx-hal`.
To learn more, run the command again with --verbose. That is strange, because mapr method is public according to https://docs.rs/stm32f1xx-hal/0.2.1/stm32f1xx_hal/afio/struct.MAPR.html#method.mapr |
You're using version 0.5.3 of the crate but looking at the 0.2.1 version of the documentation. |
@arrowcircle try again |
@therealprof , @burrbull Thanks! I was able to compile without errors and warnings. Here is example code: #![deny(unsafe_code)]
#![no_std]
#![no_main]
use panic_halt as _;
use stm32f1xx_hal::{prelude::*, can};
use cortex_m_rt::{entry, exception, ExceptionFrame};
extern crate cortex_m_semihosting;
use cortex_m_semihosting::hio;
use core::fmt::Write;
#[entry]
fn main() -> ! {
let config = can::Configuration {
time_triggered_communication_mode: false,
automatic_bus_off_management: true,
automatic_wake_up_mode: true,
no_automatic_retransmission: false,
receive_fifo_locked_mode: false,
transmit_fifo_priority: false,
silent_mode: false,
loopback_mode: true,
synchronisation_jump_width: 1,
bit_segment_1: 3,
bit_segment_2: 2,
time_quantum_length: 6,
};
let dp = stm32f1xx_hal::stm32::Peripherals::take().unwrap();
let mut rcc = dp.RCC.constrain();
let mut gpioa = dp.GPIOA.split(&mut rcc.apb2);
let canrx = gpioa.pa11.into_floating_input(&mut gpioa.crh);
let cantx = gpioa.pa12.into_alternate_push_pull(&mut gpioa.crh);
//remapped version:
//let mut gpiob = dp.GPIOB.split(&mut rcc.apb2);
//let canrx = gpiob.pb8.into_floating_input(&mut gpiob.crh);
//let cantx = gpiob.pb9.into_alternate_push_pull(&mut gpiob.crh);
let mut afio = dp.AFIO.constrain(&mut rcc.apb2);
//USB is needed here because it can not be used at the same time as CAN since they share memory:
let mut can = can::Can::can1(
dp.CAN1,
(cantx, canrx),
&mut afio.mapr,
&mut rcc.apb1,
dp.USB,
);
can.configure(&config);
nb::block!(can.to_normal()).unwrap(); //just to be sure
let id10: can::Id = can::Id::new_standard(10);
let id11: can::Id = can::Id::new_standard(11);
let id12: can::Id = can::Id::new_standard(12);
let id13: can::Id = can::Id::new_standard(13);
let id14: can::Id = can::Id::new_standard(14);
let id15: can::Id = can::Id::new_standard(15);
let filterbank0_config = can::FilterBankConfiguration {
mode: can::FilterMode::List,
info: can::FilterInfo::Whole(can::FilterData {
id: id10.clone(),
mask_or_id2: id11.clone(),
}),
fifo_assignment: 0,
active: true,
};
let filterbank1_config = can::FilterBankConfiguration {
mode: can::FilterMode::List,
info: can::FilterInfo::Whole(can::FilterData {
id: id12.clone(),
mask_or_id2: id13.clone(),
}),
fifo_assignment: 1,
active: true,
};
let filterbank2_config = can::FilterBankConfiguration {
mode: can::FilterMode::List,
info: can::FilterInfo::Whole(can::FilterData {
id: id14.with_rtr(),
mask_or_id2: id14.clone(),
}),
fifo_assignment: 0,
active: true,
};
let filterbank3_config = can::FilterBankConfiguration {
mode: can::FilterMode::List,
info: can::FilterInfo::Whole(can::FilterData {
id: id15.with_rtr(),
mask_or_id2: id15.clone(),
}),
fifo_assignment: 1,
active: true,
};
can.configure_filter_bank(0, &filterbank0_config);
can.configure_filter_bank(1, &filterbank1_config);
can.configure_filter_bank(2, &filterbank2_config);
can.configure_filter_bank(3, &filterbank3_config);
let mut hstdout = hio::hstdout().unwrap();
let (tx, rx) = can.split();
let (mut tx0, mut tx1, mut tx2) = tx.split();
let txresult0 = tx0.request_transmit(&can::Frame::new(id10, can::Payload::new(b"0")));
let txresult1 = tx1.request_transmit(&can::Frame::new(id11, can::Payload::new(b"1")));
let txresult2 = tx2.request_transmit(&can::Frame::new(id12, can::Payload::new(b"2")));
writeln!(
hstdout,
"tx: {:?} {:?} {:?}",
&txresult0, &txresult1, &txresult2
).unwrap(); //while this printing slowly, all 3 messages are transfered
let txresult0 = tx0.request_transmit(&can::Frame::new(id13, can::Payload::new(b"3")));
let txresult1 = tx1.request_transmit(&can::Frame::new(id14, can::Payload::new(b"4")));
let txresult2 = tx2.request_transmit(&can::Frame::new(id15, can::Payload::new(b"5")));
writeln!(
hstdout,
"tx: {:?} {:?} {:?}",
&txresult0, &txresult1, &txresult2
).unwrap(); //while this printing slowly, all 3 messages are transfered
let (mut rx0, mut rx1) = rx.split();
loop {
if let Ok((filter_match_index, time, frame)) = rx0.read() {
writeln!(
hstdout,
"rx0: {} {} {} {} {}",
filter_match_index,
frame.id().standard(),
time,
frame.data().len(),
frame.data().data_as_u64()
).unwrap();
};
if let Ok((filter_match_index, time, frame)) = rx1.read() {
writeln!(
hstdout,
"rx1: {} {} {} {} {}",
filter_match_index,
frame.id().standard(),
time,
frame.data().len(),
frame.data().data_as_u64()
).unwrap();
};
}
//writeln!(hstdout, "done.").unwrap();
}
#[exception]
fn HardFault(ef: &ExceptionFrame) -> ! {
panic!("{:#?}", ef);
}
#[exception]
fn DefaultHandler(irqn: i16) {
panic!("Unhandled exception (IRQn = {})", irqn);
} and semihosting output tx: Ok(()) Ok(()) Ok(())
tx: Ok(()) Ok(()) Ok(())
rx0: 0 11 0 1 49
rx1: 0 13 0 1 51
rx0: 2 14 0 1 52
rx1: 2 15 0 1 53 Does it look like a valid result? |
@arrowcircle the output seems to be right:
|
Should we convert this example to some kind of hardware running unit tests? |
Adapted from: stm32-rs#101
I’m working on this to add support for the stm32f105/107 devices.
I will open a new pull request once I completed them all. |
That will be nice, thanks! |
Indeed for stm32f105/107 CAN does not share memory with the USB peripheral. |
Nice! What about CAN related interrupts? Do they need some helper functions? |
Thank you for reminding. |
Hey! Thanks for the contribution. I was experimenting with this code for 4 days and was struggling to get real communications working. Looks like I got malfunctioning bluepill, but I found this only on day 4 :(. In general, this implementation does not have prescaler parameter to configure bit timing. And example does not show anything about speed clock and so on. I think we should have few examples:
Does it look sane? |
Yes, debugging HW is tricky even if you have a oscilloscope, like me :P.
This is a low level driver, more comfortable, but less capable abstractions like the one proposed in the embedded-hal crate can be built on the top of this later.
|
@tib888 Thanks for the answer. Could you please verify my thought? SJW = 1, Clock rate= 8Mhz, Sample Point = 87.5, speed = 500kbit/s
First row is preferred. Is it right, that I need to set bit_segment_1= 13, bit_segment_2= 2, time_quantum_length = 16 to have 500kbit/s? What is the thing with SN65HVD230? Any links? |
Almost correct: |
14/(14+2) = 0.875 So I think you should fill the config struct like this: but the register will contain each value - 1:
|
You need a CAN bus driver to connect your blue pill to the can bus. |
@tib888 I am about this part:
As I understand, time_quantum_length should equal Prescaler (from the table)? Also, why values of bit segments are substracted by 1? This looks really confusing, isn't it? |
If you order something cheap from China such things can happen...
cpu_clock / perscale gives you a clock, from this clock bit_segment_1 + bit_segment_2 pulses used during one bit detection on the can bus.
The allowed range of values is 1..16 or 1..8, and for the prescale 1..1024 (zero makes no sense). |
Now I am 100% confused.
Where 14 comes from? Sorry for stupid questions, but could you please explain how to properly init CAN BUS with values from http://www.bittiming.can-wiki.info/ ? For example, lets get clock = 8MHz
for 1000 kbit/s
for 500 kbit/s
for 125 kbit/s
Is it right? If yes, how should CAN BUS initialize? for 1000 kbit/s let config = can::Configuration {
time_triggered_communication_mode: false,
automatic_bus_off_management: true,
automatic_wake_up_mode: true,
no_automatic_retransmission: false,
receive_fifo_locked_mode: false,
transmit_fifo_priority: false,
silent_mode: false,
loopback_mode: false,
synchronisation_jump_width: 1,
bit_segment_1: 7,
bit_segment_2: 2,
time_quantum_length: 2,
}; for 500 kbit/s let config = can::Configuration {
time_triggered_communication_mode: false,
automatic_bus_off_management: true,
automatic_wake_up_mode: true,
no_automatic_retransmission: false,
receive_fifo_locked_mode: false,
transmit_fifo_priority: false,
silent_mode: false,
loopback_mode: false,
synchronisation_jump_width: 1,
bit_segment_1: 14,
bit_segment_2: 3,
time_quantum_length: 2,
}; for 125 kbit/s let config = can::Configuration {
time_triggered_communication_mode: false,
automatic_bus_off_management: true,
automatic_wake_up_mode: true,
no_automatic_retransmission: false,
receive_fifo_locked_mode: false,
transmit_fifo_priority: false,
silent_mode: false,
loopback_mode: false,
synchronisation_jump_width: 1,
bit_segment_1: 14,
bit_segment_2: 3,
time_quantum_length: 5,
}; |
After few experiments, I found this configuration valid for 500 kbit/s let config = can::Configuration {
time_triggered_communication_mode: false,
automatic_bus_off_management: true,
automatic_wake_up_mode: true,
no_automatic_retransmission: false,
receive_fifo_locked_mode: false,
transmit_fifo_priority: false,
silent_mode: false,
loopback_mode: false,
synchronisation_jump_width: 1,
bit_segment_1: 13,
bit_segment_2: 2,
time_quantum_length: 1,
}; |
My attempts to continue this work can be found on my fork of the repo. I wasn’t able to get the receiver working. |
looking at the code, the documentation dded to be fixed here: And below that there is a comment, which I think valid: remove pub |
This seems to now be superseded by #215 so I'll go ahead and close, Feel free to re-open if that's the wrong call :) |
This old CAN implementation was done by @tib888 for stm32f103xx.
Maybe someone will be interested and test it.