-
Notifications
You must be signed in to change notification settings - Fork 231
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
[#80] Baudrate type implementation #88
Conversation
My suggestion would be to start working on this for one board only (preferably some hardware you have and can test things on). Once discussion about the design has settled and all problems are ironed out, it can be transferred to all other crates as well. This way, you don't have to make each change for all the crates every time. |
@Rahix tested default on arduino leonardo. Do you have any specific scenarios for tests? |
@explicite, my suggestion was to remove the changes from all board code except
We should test all the well known baudrates, ideally also with different core clock speeds. Not sure how to easily try other clock speeds though (maybe by setting the clock prescaler?).
I guess this would be the right thing to do but we don't really have a testing infrastructure yet ... I think manual testing is enough for now. |
avr-hal-generic/src/serial.rs
Outdated
let mut baud_setting = (CLOCK::FREQ / 4 / baud - 1) / 2; | ||
let mut u2x = true; | ||
|
||
// Switch back from u2x if required | ||
if ((CLOCK::FREQ == 16_000_000) && (baud == 57_600)) || (baud_setting > 4095) { | ||
u2x = false; | ||
baud_setting = (CLOCK::FREQ / 8 / baud - 1) / 2; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what Arduino is doing but especially that workaround for their bootloader seems suspicious to me. We have to remember that not everyone using the HAL is using it for Arduino boards so we should be careful about shipping Arduino workarounds everywhere by default. I'll look deeper into this and share my results.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, enabling U2X consistently yields clock rates with equal or less error than with disabled U2X so I'd say it should be the default where possible. I.e. it makes sense to ship this algorithm in the Baudrate::new()
method.
The workaround ((CLOCK::FREQ == 16_000_000) && (baud == 57_600))
) is really not something we want to include by default, however. It actually makes the clock error worse, going from -0.8%
(with u2x) to +2.1%
(without u2x). This is (apparently) necessary because the USB-to-Serial bridge on some arduino boards has a firmware with a similar clock error and the -0.8%
in the other direction would make the total error 3%
which is too much, I guess.
My suggestion would be to add a custom BaudrateArduinoExt
trait where the fix is applied. On the affected boards, BaudrateArduinoExt
is pulled into the prelude instead of BaudrateExt
.
pub trait BaudrateArduinoExt {
fn into_baudrate<CLOCK: crate::clock::Clock>(self) -> Baudrate<CLOCK>;
}
impl BaudrateArduinoExt for u32 {
fn into_baudrate<CLOCK: crate::clock::Clock>(self) -> Baudrate<CLOCK> {
let br = Baudrate::new(self);
// hardcoded exception for 57600 for compatibility with the bootloader
// shipped with the Duemilanove and previous boards and the firmware
// on the 8U2 on the Uno and Mega 2560.
//
// https://github.com/arduino/ArduinoCore-avr/blob/3055c1efa3c6980c864f661e6c8cc5d5ac773af4/cores/arduino/HardwareSerial.cpp#L123-L132
if CLOCK::FREQ == 16_000_000 && br.ubrr == 34 && br.u2x {
// (CLOCK::FREQ / 8 / 57600 - 1) / 2 == 16
Baudrate::with_exact(false, 16)
} else {
br
}
}
}
The only problem I see with this is that it's a bit "magical" and makes it quite non-obvious which version is used. Though the alternative of requiring board users to explicitly do something different depending on the hardware they are using, is against the idea of having a HAL in the first place ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I done this. Now I'm testing leonardo-serial
example. After upload, arduino is not recognized until I will reset. After that I need to cleanup board to works fine without reset.
I'm not sure if it's regression, serial example (need to spend some more time on example itself) or problem with .elf
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, you're probably trying to access the serial console directly via the USB cable which you use to flash code to the board? That's not going to work on Leonardo as it is different from the other Arduino boards: On other Arduinos there is a separate USB-to-Serial converter between the USB port and the actual MCU. On Leonardo, the USB port is directly connected to the MCU (ATmega32U4) and for Arduino C code, the MCU directly presents itself to the host as a USB-to-Serial converter. In Rust we don't do that (at this time at least). Instead, what you're working with right now is the real USART peripheral connected to the pins D0 (RX) and D1 (TX). So to access it you'll need a separate USB-to-Serial converter to connect to those pins.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, I have some usb to ttl from my old ESP project. After quick test I was able to send some chars with let baudrate = 9600_u32.into_baudrate();
and receive correct response: Will test below combination - with Ext. impl and with exact ubrr
baund | UBRR | tested |
---|---|---|
300 | 767 | ok |
600 | 383 | ok |
1200 | 191 | ok |
2400 | 95 | ok |
4800 | 47 | ok |
9600 | 23 | ok |
14400 | 15 | failed |
19200 | 11 | ok |
28800 | 7 | failed |
38400 | 5 | ok |
57600 | 3 | ok |
76800 | 2 | failed |
115200 | 1 | ok |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That aside, we should also run a test on an Arduino Uno with the special implementation to check whether that's working as intended. If you don't have a device on hand, I can take care of that :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will be able to test with uno in the end of this week. So if with your help we can be faster.
PL-2303HX should support some of the bauds. http://www.prolific.com.tw/UserFiles/files/ds_pl2303HXD_v1_4_4.pdf
Not sure about linux drivers. Right now I'm on 5.4.0-52-generic and I can see it. Not sure if supports all bauds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Linux will just pass the baudrate to the CDC-ACM endpoint exposed by your PL-2303HX. What the device makes of it is the important part, some just select the closest baudrate, others properly configure their clock for the exact selected speed.
From the datasheet you linked, at least 14400 and 28800 should work though ... You don't by any chance have an oscilloscope at hand to check the signal? I'm a bit short on time this and the next week. Though after that I could run some intrusive tests to see.
That said, I wouldn't block this PR's progress on these few baudrates though. As long as all common rates are well supported, we are good I'd say.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not have any oscilloscope now. With time I will buy some. I don't want to invest to much now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's open an issue for this an resolve it at a later time: #99
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the technical side, I think we're all good now! I've left a few comments related to cleanup, please take care of them. Afterwards, let's do some more tests to make sure it's working correctly now and then fixup all the other HAL & Board crates where necessary. Thanks for working on this :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have some more minor style nit-picks, but apart from that it's looking really good!
Once you've got those applied, please go ahead and apply the same changes as in boards/arduino-leonardo/src/lib.rs
to all the other board crates. We'll have to check which ones need the fixed ..Ext
trait and which don't. AFAIK at least arduino-uno
and arduino-diecimila
will need it. Then, of course all the examples need an update as well.
Oh, and feel free to remove the "Draft" state from this PR :) |
@Rahix should I implement same changes for other chips and boards? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think it looks good now! Please do the changes from boards/arduino-leonardo/src/lib.rs
for all the other boards as well now. That means, apply the following changeset:
@@ -54,7 +54,11 @@ pub use crate::pac::Peripherals;
mod pins;
pub use crate::pins::*;
-pub use crate::hal::prelude;
+pub mod prelude {
+ pub use crate::hal::prelude::*;
+ pub use crate::hal::usart::BaudrateExt as _;
+}
+pub use crate::hal::usart;
/// Busy-Delay
///
@@ -187,7 +191,7 @@ pub mod pwm {
/// dp.USART1,
/// pins.d0,
/// pins.d1.into_output(&mut pins.ddr),
-/// 57600,
+/// 57600.into_baudrate(),
/// );
///
/// ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").void_unwrap();
Of course you'll also have to fix all the relevant examples alongside it:
let mut serial = <board>::Serial::new(
dp.USART1,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
- 57600,
+ 57600.into_baudrate(),
);
@Rahix I think all fixed as required. Should I made any changes/testing? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking pretty good! Only thing we need to change is making use of the special implementation on affected boards. We should test where it applies, I've marked the potential candidates with comments:
pub use crate::hal::prelude; | ||
pub mod prelude { | ||
pub use crate::hal::prelude::*; | ||
pub use crate::hal::usart::BaudrateExt as _; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also need to check whether this is affected by the special implementation. @couchand, maybe you can give a try of this PR at 57600 baud?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In worst case I think will be able to test this in next week.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For mega2560 same results. I will check now Uno rev3 for same baunds
baund | UBRR | tested |
---|---|---|
300 | 767 | ok |
600 | 383 | ok |
1200 | 191 | ok |
2400 | 95 | ok |
4800 | 47 | ok |
9600 | 23 | ok |
14400 | 15 | failed |
19200 | 11 | ok |
28800 | 7 | failed |
38400 | 5 | ok |
57600 | 3 | ok |
76800 | 2 | failed |
115200 | 1 | ok |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is with the BaudrateExt
trait, right? So it seems 57600 and 115200 are working fine with the default implementation which means we don't need to switch for this board!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Looks like works fine. I'm able to test today uno rev3 too. Then I will need to reupload bootloader for mega2560...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you don't have any objections, I'm content with the results you provided and would go ahead with merging your PR now. Thank you so much for you work here! You were a lot more thorough than most people would be which I appreciate a lot. :)
Looks like you'll need to fix merge conflicts/rebase your branch once more, then I can merge it :) |
Base impl. for discussion