Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

Target microcontroller directly instead of an arduino board #125

Closed
derchr opened this issue Jan 29, 2021 · 10 comments
Closed

Target microcontroller directly instead of an arduino board #125

derchr opened this issue Jan 29, 2021 · 10 comments
Labels
question Further information is requested

Comments

@derchr
Copy link

derchr commented Jan 29, 2021

Hello,
I'm new to avr-rust and Rust in general.
All examples I see in this repository seem to target a board (for example Arduino Uno). Is it possible or recommended to directly target a microcontroller such as atmega328p?
I found no example and had trouble while trying to do so.
I added those lines to the Cargo.toml:

[dependencies.atmega328p-hal]
git = "https://github.com/Rahix/avr-hal"
rev = "206ff87bdc38afcffd9db1c9326c0d4d9487cb14"
features = ["atmega328p"]

[dependencies.avr-hal-generic]
git = "https://github.com/Rahix/avr-hal.git"
rev = "206ff87bdc38afcffd9db1c9326c0d4d9487cb14"

Do I need to write something like #[avr_device::entry] instead of #[arduino_uno::entry] in the source file? Or how can I use the needed prelude?

Thank you in advance!

@Rahix
Copy link
Owner

Rahix commented Jan 30, 2021

Hi!

All examples I see in this repository seem to target a board (for example Arduino Uno).

That's just because most people will be using one of those boards so that's what we tried making the easiest to get started with. Also, it is hard to write examples against a generic MCU, because you have no clue what peripherals are connected and could be used...

Is it possible or recommended to directly target a microcontroller such as atmega328p?

It really depends on the usecase I'd say. Is it a one-off application for a custom design? Then I'd just go with the HAL (atmega328p-hal in your case). Is it a custom board for which you intend to write multiple programs? In this case I would suggest creating a custom board crate, to make application development smoother.

I added those lines to the Cargo.toml:

You really just need atmega328p-hal. E.g.

[dependencies.atmega328p-hal]
git = "https://github.com/Rahix/avr-hal"
rev = "206ff87bdc38afcffd9db1c9326c0d4d9487cb14"
features = ["atmega328p", "rt"]

Note the rt feature. This is necessary to enable the "runtime", which in this case is just the startup and interrupt code. It should be enabled in application crates. If this feature is enabled you can then use the entry macro in your code:

#[atmega328p_hal::entry]
fn main() -> ! {
    // ...
}

Or how can I use the needed prelude?

Instead of the board prelude, you'd go with the HAL prelude. E.g.

use atmega328p_hal::prelude::*;

Hope this helps! If you need anything else, let me know :)

@Rahix Rahix added the question Further information is requested label Jan 30, 2021
@Rahix
Copy link
Owner

Rahix commented Jan 30, 2021

One more thing which might be important: The board support crates re-export the bare MCU pins (PA0, PB3, etc.) in this Pins struct where they have the board-specific names (D0, D1, ...). This is of course not available if you use the MCU HAL directly. So instead of

let dp = arduino_uno::Peripherals::take().unwrap();

let mut pins = arduino_uno::Pins::new(dp.PORTB, dp.PORTC, dp.PORTD);

let mut led = pins.d0.into_output(&mut pins.ddr);

you'd have to write

let dp = atmega328p_hal::pac::Peripherals::take().unwrap();

let mut portb = dp.PORTB.split();

let mut led = portb.pb0.into_output(&mut portb.ddr);

(This works via the PortExt trait...)

@derchr
Copy link
Author

derchr commented Jan 30, 2021

@Rahix
Thank you for your very detailed answer :)
It works now like a charm!

Is it a one-off application for a custom design?

Yes, it's a special use case with a custom made PCB.

Note the rt feature.

Ah, yes this was missing too.

@derchr
Copy link
Author

derchr commented Feb 2, 2021

I might have one last question. In my program I need to access a peripheral in a ISR, so I have to share the peripherals in some way. The Rust Embedded Book takes an approach with an Mutex<RefCell<Option<T>>>.

However when I try to use this approach in my program I get weird linker errors (the compilation is fine) as soon as I do something like this in my critical section:

LED_PIN.borrow(cs).replace(None);
Errors:
error: linking with `avr-gcc` failed: exit code: 1
  |
  = note: "avr-gcc" "-mmcu=atmega328p" "-Wl,--as-needed" "-L" "/home/user/.rustup/toolchains/nightly-2021-01-07-x86_64-unknown-linux-gnu/lib/rustlib/avr-atmega328p/lib" "/home/user/Projekte/AVR/rust-playground/target/avr-atmega328p/debug/deps/rust_playground-9dbe6fbfbe199f10.embedded_time-9481653159125601.embedded_time.bdoom5vi-cgu.0.rcgu.o.rcgu.o" "-o" "/home/user/Projekte/AVR/rust-playground/target/avr-atmega328p/debug/deps/rust_playground-9dbe6fbfbe199f10.elf" "-Wl,--gc-sections" "-no-pie" "-L" "/home/user/Projekte/AVR/rust-playground/target/avr-atmega328p/debug/deps" "-L" "/home/user/Projekte/AVR/rust-playground/target/debug/deps" "-L" "/home/user/.rustup/toolchains/nightly-2021-01-07-x86_64-unknown-linux-gnu/lib/rustlib/avr-atmega328p/lib" "-Wl,--start-group" "-Wl,--end-group" "-Wl,-Bstatic" "/home/user/Projekte/AVR/rust-playground/target/avr-atmega328p/debug/deps/libcompiler_builtins-42d057ec80fb5f3c.rlib" "-Wl,-Bdynamic" "-lgcc"
  = note: /usr/lib64/gcc/avr/10/ld: warning: -z relro ignored
          /usr/lib64/gcc/avr/10/ld: /home/user/Projekte/AVR/rust-playground/target/avr-atmega328p/debug/deps/libcompiler_builtins-42d057ec80fb5f3c.rlib(compiler_builtins-42d057ec80fb5f3c.compiler_builtins.8twx0hi5-cgu.7.rcgu.o): in function `_ZN17compiler_builtins3int5shift4Ashl4ashl17he5d1eaad1e748b29E':
          /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.36/src/int/shift.rs:(.text._ZN17compiler_builtins3int5shift4Ashl4ashl17he5d1eaad1e748b29E+0x150): undefined reference to `_ZN4core9panicking5panic17h1399af0e0fccbeebE'
          /usr/lib64/gcc/avr/10/ld: /home/user/Projekte/AVR/rust-playground/target/avr-atmega328p/debug/deps/libcompiler_builtins-42d057ec80fb5f3c.rlib(compiler_builtins-42d057ec80fb5f3c.compiler_builtins.8twx0hi5-cgu.7.rcgu.o): in function `_ZN17compiler_builtins3int5shift4Lshr4lshr17h65e5db2cab149a54E':
          /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.36/src/int/shift.rs:(.text._ZN17compiler_builtins3int5shift4Lshr4lshr17h65e5db2cab149a54E+0x1f8): undefined reference to `_ZN4core9panicking5panic17h1399af0e0fccbeebE'
          /usr/lib64/gcc/avr/10/ld: /home/user/Projekte/AVR/rust-playground/target/avr-atmega328p/debug/deps/libcompiler_builtins-42d057ec80fb5f3c.rlib(compiler_builtins-42d057ec80fb5f3c.compiler_builtins.8twx0hi5-cgu.1.rcgu.o): in function `_ZN17compiler_builtins3int19specialized_div_rem11u32_div_rem17h6933462051ddbcc7E':
          /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.36/src/int/specialized_div_rem/norm_shift.rs:(.text._ZN17compiler_builtins3int19specialized_div_rem11u32_div_rem17h6933462051ddbcc7E+0x718): undefined reference to `_ZN4core9panicking5panic17h1399af0e0fccbeebE'
          collect2: error: ld returned 1 exit status
          

error: aborting due to previous error; 2 warnings emitted

@Rahix
Copy link
Owner

Rahix commented Feb 2, 2021

Heh, yeah, that's a known issue: rust-lang/compiler-builtins#347

There is a dirty workaround to add the following to your Cargo.toml:

[profile.dev.package.compiler_builtins]
overflow-checks = false

cargo will warn about this but it'll still work fine... Alternatively compile in release mode where overflow-checks are always disabled.

@derchr
Copy link
Author

derchr commented Feb 2, 2021

I see. Many thanks!

@derchr
Copy link
Author

derchr commented Feb 24, 2021

Hey @Rahix!
Thanks to your amazing work on avr-hal and your help I was able to port an old project from C to Rust. In case you are interested, here is a link: https://github.com/4VRDriver/EQPlatform-Guiding/tree/Rust/firmware.
Although it is not completely finished yet and some things should be improved, it's now as functional my old C code.

@Rahix
Copy link
Owner

Rahix commented Feb 24, 2021

Can't say I fully understand what the project is about, but it looks really neat! Is it a controller for a telescope mount?

I see you also wrote an EEPROM driver. Would you be interested in upstreaming that into avr-hal?

Also, do you have any feedback regarding your experience with using avr-hal & avr-device? What were the main painpoints? Were there any things where you had to "work around" the API because it hindered you from doing what you needed to? Are there any big missing things which would have helped you a lot?

@derchr
Copy link
Author

derchr commented Feb 24, 2021

Thanks!

Is it a controller for a telescope mount?

Yes exactly. The core functionality is to control a stepper motor which controls a telescope mount. The speed of the motor can be adjusted by trail and error using a Bluetooth module. Using this technique I was able to get a very good improvement in visual observation. As an additional improvement I thought of introducing a feedback loop that tries to hold a star in place with a webcam and therefore send guiding pulses to the stepper motor. This is what the C++ driver is for but unfortunately I never got this to work in a way that it actually could improve things.

I see you also wrote an EEPROM driver. Would you be interested in upstreaming that into avr-hal?

I could actually imagine to work on such a feature but I think my current code isn't sophisticated enough yet to upstream it.

Also, do you have any feedback regarding your experience with using avr-hal & avr-device?

Well because I was new to Embedded Rust, I was confused at first by understanding the difference between the pac module and all of the other modules.
I also had a hard time dealing with all the very lengthy types when creating static variables. For example my UsartReader has this type

hal::usart::UsartReader<hal::pac::USART0, hal::port::portd::PD0<hal::port::mode::Input<hal::port::mode::Floating>>, hal::port::portd::PD1<hal::port::mode::Output>, hal::clock::MHz16>;

Eventually I could shorten this by utilizing some use statements but it always felt very odd to me.

Were there any things where you had to "work around" the API because it hindered you from doing what you needed to?

I don't think so, except for the timer and eeprom which obviously had to be implemented by accessing the registers manually.

@Rahix
Copy link
Owner

Rahix commented Feb 24, 2021

Yes exactly. The core functionality is to control a stepper motor which controls a telescope mount. The speed of the motor can be adjusted by trail and error using a Bluetooth module. Using this technique I was able to get a very good improvement in visual observation. As an additional improvement I thought of introducing a feedback loop that tries to hold a star in place with a webcam and therefore send guiding pulses to the stepper motor. This is what the C++ driver is for but unfortunately I never got this to work in a way that it actually could improve things.

That's amazing!

Well because I was new to Embedded Rust, I was confused at first by understanding the difference between the pac module and all of the other modules.

Yeah, you're not alone with that, I've gotten that report from quite a few people now... I think I can maybe add some sort of overview to the README which explains how all the parts fit together.

I also had a hard time dealing with all the very lengthy types when creating static variables. For example my UsartReader has this type

Right... I think the only real way to mitigate this would be creating type aliases in the relevant HAL crates directly which downstream code can then just reference easily. I'll have a look what is possible here.

Repository owner locked and limited conversation to collaborators Sep 2, 2022
@Rahix Rahix converted this issue into discussion #318 Sep 2, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants